- set value in application.properties
efs.url=http://efs-beta.test.com
- inject value in Service
@Data
@Named
public class DimensionService implements IDimensionService {
@Value("${efs.url}")
public String efsUrl;
}
- run test
public class IDimensionServiceTest{
@Inject
private DimensionService dimensionService;
@Test
public void test() {
System.out.println(dimensionService.getEfsUrl() "\t" dimensionService.efsUrl);
}
}
- console print
http://efs-beta.test.com null
why connot get public field by @Value directly?
CodePudding user response:
If you are running a test, check that you are setting the parameter in the test package as well It is recommended to use yml files for configuration visit https://www.baeldung.com/spring-value-annotation
CodePudding user response:
dimensionService.getClass()
returnsxxx.DimensionService$$EnhancerBySpringCGLIB$$eda602b7
That's a runtime generatated subclass of DimensionService
, most likely a Spring AOP proxy. Spring AOP allows for aspect oriented programming (AOP), which is a way to implement cross cutting concerns, which are things that need to be done in the same way in many, otherwise unrelated, methods in your program.
For instance, that's how Spring implements its @Transactional
, which adds code for starting, committing and rolling back transactions to all methods bearing this annotation (or which are otherwise configured to be transactional). That's also how Spring implements @Timed
for collecting runtime metrics, and many other things.
That is, Spring AOP allows for attaching additional code to methods of beans that satisfy some criteria. To attach this additional code, Spring AOP uses a proxy object. For instance, if you have
class X {
@Inject
Y y;
}
class Y {
public void foo() {
// do something
}
}
Spring AOP will, at runtime, generate an additional class like this:
class Y$$EnhancedBySpringCGLIB$$eda602b7 extends Y {
Y target;
@Override
public void foo() {
// do things before
var result = target.foo();
// do things after
return result;
}
}
and inject an instance of that class into everyone that asks for a Y
. That is, at runtime, we have the following objects:
-------
| X |
-------
|
|
v
------------------
| Y$$EnhancerBy... |
------------------
|
|
v
-----
| Y |
-----
As far as possible, this proxy object mimics the behavior of the real object (with added functionality). In particular, all public methods are overridden to delegate to the real object. However, Java does not allow overriding field access, so Spring AOP can not redirect field access to the real object, and the (empty) field of the proxy will be read, breaking the illusion. Short of writing a compiler plugin, and requiring all code that may access these fields to be compiled by that plugin, there is nothing Spring AOP can do to fix this.
This means that whenever you are accessing a Spring bean, you should do so through its public methods (and on a reference that you obtained from Spring - this
points to the real object, not the proxy, and doesn't have the additional functionality).
Further information about Spring AOP is available in the Spring reference manual, specifically in Aspect Oriented Programming with Spring and Understanding AOP Proxies.