Cannot enhance @Configuration bean definition ‘xxx‘ * since its singleton instance has been create

项目启动过程中,控制台打印了如下日志
"Cannot enhance @Configuration bean definition 'xxx' 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'."

意思是: 无法增强@Configuration注解得名字为xxx的bean,原因是这个类被实例化太早了,最常见的原因就是在配置类中使用@Bean标记了一个BeanDefinitionRegistryPostProcessor接口的实现类.考虑使用static去修改这个方法。

1 、本人并没有像警告信息里说的那样在一个配置类中使用@Bean去注入BeanDefinitionRegistryPostProcessor的实现类,但是导致抛出这个警告的原因是一样的.
先看代码复现下该警告,只需要如下代码即可:

@Configuration
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

public MyBeanDefinitionRegistryPostProcessor() {
   System.out.println();
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
   System.out.println();
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
   System.out.println();
  }
}

运行结果如下:

通过日志可以看出,该信息在org.springframework.context.annotation.ConfigurationClassPostProcessor中打印,下面来看一下为什么会打印这个警告?

首先ConfigurationClassPostProcessor 实现了接口BeanFactoryPostProcessor, 并在方法postProcessBeanFactory中对所有的@Configuration类进行cglib增强,动态生成配置类的子类,在实例化配置类时是通过子类创建的Bean实例.
 

full config: 就是被@Configuration注解标记的配置类, 但是如果配置类在增强之前就被调用getBean()实例化了,就会打印我们所看到的警告信息. 

那么我们的MyBeanDefinitionRegistryPostProcessor为什么会在增强之前被实例化呢? 

原因就在于其实现了接口BeanDefinitionRegistryPostProcessor,该接口是BeanFactoryPostProcessor的子类,当调用org.springframework.context.support.AbstractApplicationContext refresh()方法时会调用invokeBeanFactoryPostProcessors()而该方法中会优先通过getBeanNamesForType() 找到所有的BeanDefinitionRegistryPostProcessor实现类并通过getBean创建bean实例,并遍历调用接口方法postProcessBeanDefinitionRegistry, 其优先于父类接口BeanFactoryPostProcessor的实例执行, 而@Configuration配置类的增强是在BeanFactoryPostProcessor的实现类ConfigurationClassPostProcessor的postProcessBeanFactory方法中执行的,这就导致了MyBeanDefinitionRegistryPostProcessor被提前实例化了, 所以出现了我们所看到的警告信息.
       这个警告信息一般情况下不影响我们的程序运行,当我们仅需要使用的BeanDefinitionRegistryPostProcessor实现类,不需要复杂的配置信息时,可以通过使用@component注解来替换@Configuration.

2、警告中所说的考虑使用static修饰方法是什么情况呢?如下代码其实也会导致出现我们看到的警告信息

@Configuration
public class MyConfig {

    public MyConfig() {
        System.out.println();
    }

    @Bean
    public BeanDefinitionRegistryPostProcessor myBeanDefRegPostProcessor() {
        return new MyBeanDefinitionRegistryPostProcessor();
    }

   // 使用static方法则不会打印警告
   // @Bean 
   // public static BeanDefinitionRegistryPostProcessor myBeanDefRegPostProcessor() { 
   //     return new MyBeanDefinitionRegistryPostProcessor(); 
   // }
}

原因是当获取BeanDefinitionRegistryPostProcessor接口的bean时,会调用myBeanDefRegPostProcessor()方法创建Bean,而调用该方法前同样需要先实例化MyConfig,导致了MyConfig在被增强之前被实例化了, 而如果把方法修饰为static,static方法属于类方法,就不会触发MyConfig被提前实例化也就不会出现警告信息了.

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值