不直接通过@Value获取公共字段


  • 在application.properties中设置值
    efs.url=http://efs-beta.test.com
  • 在服务中注入价值
@Data
@Named
public class DimensionService implements IDimensionService {
@Value("${efs.url}")
public String efsUrl;
}
  • 运行测试
public class IDimensionServiceTest{
@Inject
private DimensionService dimensionService;
@Test
public void test() {
System.out.println(dimensionService.getEfsUrl() + "t" + dimensionService.efsUrl);
}
}
  • 控制台打印
    http://efs-beta.test.com null

为什么不能直接通过@Value获取公共字段?

dimensionService.getClass()返回xxx.DimensionService$$EnhancerBySpringCGLIB$$eda602b7

这是DimensionService的运行时生成的子类,很可能是SpringAOP代理。Spring AOP允许面向方面编程(AOP(,这是一种实现横切关注点的方法,这些关注点需要在程序中的许多其他无关方法中以相同的方式完成。

例如,Spring就是这样实现它的@Transactional的,它将用于启动、提交和回滚事务的代码添加到所有带有此注释的方法(或以其他方式配置为事务的方法(。这也是Spring实现@Timed的方式,用于收集运行时度量以及许多其他内容。

也就是说,SpringAOP允许将额外的代码附加到满足某些标准的bean方法。为了附加这些附加代码,SpringAOP使用了一个代理对象。例如,如果你有

class X {
@Inject
Y y;
}
class Y {
public void foo() {
// do something
}
}

Spring AOP将在运行时生成一个额外的类,如下所示:

class Y$$EnhancedBySpringCGLIB$$eda602b7 extends Y {
Y target;
@Override
public void foo() {
// do things before
var result = target.foo();
// do things after
return result;
}
}

并将该类的实例注入到请求CCD_ 8的每个人中。也就是说,在运行时,我们有以下对象:

+-------+
|   X   |
+-------+
|
|
v
+------------------+
| Y$$EnhancerBy... |
+------------------+
|
|
v
+-----+
|  Y  |
+-----+

这个代理对象尽可能模仿真实对象的行为(添加了功能(。特别是,所有公共方法都被重写以委托给真实对象。然而,Java不允许重写字段访问,因此Spring AOP无法将字段访问重定向到真实对象,并且代理的(空(字段将被读取,从而打破了这种错觉。除了编写编译器插件,并要求所有可能访问这些字段的代码都由该插件编译之外,Spring AOP无法解决这一问题。

这意味着,无论何时访问Springbean,都应该通过其公共方法进行访问(在从Spring-this获得的引用上,它指向的是真实对象,而不是代理,并且没有额外的功能(。

关于Spring AOP的更多信息可以在Spring参考手册中找到,特别是在Spring的面向方面编程和理解AOP代理中。

如果您正在运行测试,请检查您是否也在测试包中设置了参数建议使用yml文件进行配置参观https://www.baeldung.com/spring-value-annotation

最新更新