Overview
If the field name for a @Lazy @Resource
does not match the bean name of the desired dependency, both CommonAnnotationBeanPostProcessor.buildLazyResourceProxy(...)
and ContextAnnotationAutowireCandidateResolver.buildLazyResolutionProxy(...)
will create proxies for the injected bean, with the latter creating a proxy that wraps the proxy created by the former.
For example, in the following test case, the fieldNameMatchesBeanName()
test passes; whereas, the fieldNameDoesNotMatchBeanName()
test fails with an error similar to the following.
Expected size: 2 but was: 3 in:
[example.LazyResourceTests$MyBean$$EnhancerBySpringCGLIB$$c2407600,
example.LazyResourceTests$MyBean$$EnhancerBySpringCGLIB$$c2407600,
example.LazyResourceTests.MyBean]
@SpringJUnitConfig
class LazyResourceTests {
@Lazy
@Resource
MyBean myBean;
@Lazy
@Resource
MyBean bean;
@Test
void fieldNameMatchesBeanName() throws Exception {
assertPathToTarget(this.myBean);
}
@Test
void fieldNameDoesNotMatchBeanName() throws Exception {
assertPathToTarget(this.bean);
}
private static void assertPathToTarget(Object beanToInspect) throws Exception {
List<Class<?>> classes = new ArrayList<>();
Object current = beanToInspect;
while (current != null) {
classes.add(current.getClass());
if (AopUtils.isAopProxy(current) && current instanceof Advised) {
current = ((Advised) current).getTargetSource().getTarget();
}
else {
break;
}
}
assertThat(classes).hasSize(2);
}
@Configuration
static class Config {
@Bean
MyBean myBean() {
return new MyBean();
}
}
static class MyBean {
}
}
Related Issues
-
28173
Comment From: sbrannen
Although the creation of two proxies for the same lazy injection point is unintentional, the team has decided to close this issue on the following grounds.
The only way for two such proxies to be created is if a @Lazy @Resource
field has a name that does not match the name of a bean in the ApplicationContext
, which should not be the case in practice.
When using @Resource
, the developer is requesting that Spring perform dependency injection by name. When the field name does not match an existing bean name, Spring's dependency resolution mechanism falls back to dependency injection by type.
Thus, if a user wishes to use @Lazy
with dependency injection by type, the injection point should be annotated with @Autowired
or @Inject
instead of @Resource
. Otherwise, the user should ensure the @Resource
field name matches an existing bean name or accept the fact that two lazy proxies are created for such scenarios.