When using Configuration annotation BeanDefinitionRegistryPostProcessor, the instance type of dependency injection is inconsistent with getBeanClassName in BeanDefinition. The code is as follows
@Configuration
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
System.out.println();
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println();
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DemoApplication.class})
public class DemoApplicationTests {
@Autowired
private ConfigurableApplicationContext context;
@Autowired
private MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor;
@Test
public void beanClassTest() {
String beanClass = myBeanDefinitionRegistryPostProcessor.getClass().getName();
String beanDefinitionBeanClass = context.getBeanFactory()
.getBeanDefinition("myBeanDefinitionRegistryPostProcessor")
.getBeanClassName();
System.out.println(beanClass);
System.out.println(beanDefinitionBeanClass);
Assert.assertEquals("beanClass should equals beanDefinitionBeanClass", beanClass, beanDefinitionBeanClass);
}
}
The reasons are as follows:
The method enhanceConfigurationClasses in org.springframework.context.annotation.ConfigurationClassPostProcessor ,as long as beanDef is a full configuration, it will be added to configBeanDefs and then generated by cglib into the new class, resulting in updating the beanClassName in BeanDefinition. The code should be changed to the following
Comment From: lgxbslgx
I submit a PR to solve this issue. The PR follows the log that says Cannot enhance @Configuration bean definition since its singleton instance has been created too early
.
In my opinion, I think we could enhance it even if it has been created. Maybe we should use the enhanced bean definition to create the new instance and override the old one.
@jhoeller What is your opinion. If you agree with me, I would modify my PR which would create the new instance instead of following the log.
Comment From: brucelwl
I submit a PR to solve this issue. The PR follows the log that says
Cannot enhance @Configuration bean definition since its singleton instance has been created too early
.In my opinion, I think we could enhance it even if it has been created. Maybe we should use the enhanced bean definition to create the new instance and override the old one.
@jhoeller What is your opinion. If you agree with me, I would modify my PR which would create the new instance instead of following the log.
@lgxbslgx @jhoeller This is not a good solution because it breaks the Spring bean singleton,because the beans created in advance have been invoked, if replacing the beans causes inconsistencies, I think it's only necessary to enhance the configuration beans that are not instantiated
Comment From: brucelwl
@lgxbslgx
It is suggested that we should change it to this way of writing.
......
else if (beanFactory.containsSingleton(beanName) && logger.isInfoEnabled()) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
else {
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
......
Comment From: lgxbslgx
else if (beanFactory.containsSingleton(beanName) && logger.isInfoEnabled()) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName .......);
}
else {
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
The code above maybe causes some problem. If beanFactory.containsSingleton(beanName)
is true
and logger.isInfoEnabled()
is false
, the configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef)
would be executed, which is not our expectation.
Comment From: brucelwl
@lgxbslgx Sorry, you're right.
Comment From: brucelwl
@lgxbslgx @sbrannen @jhoeller This problem has been reported for 9 days. Why not deal with it?
Comment From: lgxbslgx
@sbrannen @jhoeller This problem has been backlogged for a long time. Do you have time to review the PR? Thanks.
Comment From: sbrannen
MyBeanDefinitionRegistryPostProcessor
should not be annotated with @Configuration
since it is not a Java Config class.
The fact that you have annotated it with @Configuration
is why you see $$EnhancerBySpringCGLIB
appended to the class name.
How does your application behave if you annotate MyBeanDefinitionRegistryPostProcessor
with @Component
?
Comment From: brucelwl
@sbrannen Yes, using @Component would be the right performance.
Comment From: sbrannen
@sbrannen Yes, using @component would be the right performance.
Thanks for the feedback, @brucelwl.
Does that mean that we can close this issue as resolved from your end?
Comment From: brucelwl
@sbrannen Yes, using @component would be the right performance.
Thanks for the feedback, @brucelwl.
Does that mean that we can close this issue as resolved from your end?
I just think that if a developer accidentally uses @Configuration
, there will be an imperfect warning message or even a bug in this place, because the log says that there is no proxy, but it changes that class is a proxy class. If you think this is an unimportant problem, you can close this issue.
Comment From: sbrannen
Thanks for the additional input, @brucelwl.
We'll consider whether it makes sense to provide additional diagnostic information for such use cases.