没有合适的资源?快使用搜索试试~ 我知道了~
首页详解配置类为什么要添加@Configuration注解
详解配置类为什么要添加@Configuration注解
1.9k 浏览量
更新于2023-05-24
评论
收藏 1.41MB PDF 举报
主要介绍了详解配置类为什么要添加@Configuration注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
资源详情
资源评论
资源推荐

详解配置类为什么要添加详解配置类为什么要添加@Configuration注解注解
主要介绍了详解配置类为什么要添加@Configuration注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一
起学习学习吧
不加不加@Configuration导致的问题导致的问题
我们先来看看如果不在配置类上添加@Configuration注解会有什么问题,代码示例如下:
@ComponentScan("com.dmz.source.code")
//@Configuration
public class Config{
@Bean
public A a(){
return new A(dmzService());
}
@Bean
public DmzService dmzService(){
return new DmzService();
}
}
public class A {
public A(DmzService dmzService){
System.out.println("create A by dmzService");
}
}
@Component
public class DmzService {
public DmzService(){
System.out.println("create dmzService");
}
}
不添加@Configuration注解运行结果:
create dmzService
create A by dmzService
create dmzService
添加@Configuration注解运行结果:
create dmzService
create A by dmzService
在上面的例子中,我们会发现没有添加@Configuraion注解时dmzService被创建了两次, 这是因为第一次创建是被Spring容器所创建的,Spring调用这个dmzService()创建了一个Bean被放入了单例池中
(没有添加其它配置默认是单例的),第二次创建是Spring容器在创建a时调用了a(),而a()又调用了dmzService()方法。
这样的话,就出现问题了。
第一,对于dmzService而言,它被创建了两次,单例被打破了
第二,对于a而言,它所依赖的dmzService不是Spring所管理的,而是直接调用的一个普通的java method创建的普通对象。这个对象不被Spring所管理意味着,首先它的域(Scope)定义失效了,其次
它没有经过一个完整的生命周期,那么我们所定义所有的Bean的后置处理器都没有作用到它身上,其中就包括了完成AOP的后置处理器,所以AOP也失效了。
上面的分析不能说服你的话,我们可以看看官方在@Bean上给出的这一段注释
首先,Spring就在注释中指出了,通常来说,BeanMethod一般都申明在一个被@Configuration注解标注的类中,在这种情况下,BeanMethod可能直接引用了在同一个类中申明的beanMethod,就像本文
给出的例子那样,a()直接引用了dmzService(),我们重点再看看划红线的部分,通过调用另外一个beanMethod进入的Bean的引用会被保证是遵从域定义以及AOP语义的,就像getBean所做的那样。这
是怎么实现的呢?在最后被红线标注的地方也有说明,是通过在运行时期为没有被@Configuration注解标注的配置类生成一个CGLIB的子类。
源码分析源码分析
Spring是在什么时候创建的代理呢?到目前为止我们应该没有落掉Spring整个启动流程的任何关键代码,那么我们不妨带着这个问题继续往下看。目前来说我们已经阅读到了Spring执行流程图中的3-
5步,也就是org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors方法,在之前的分析中我们已经知道了,这个方法的主要作用就是执行BeanFactoryPostProcessor中的方
法,首先执行的是BeanDefinitionRegistryPostProcessor(继承了BeanFactoryPostProcessor)的postProcessBeanDefinitionRegistry方法,然后执行postProcessBeanFactory方法。而到目前为止我们并没有向容
器中注册bean工厂的后置处理器(BeanFactoryPostProcessor),这就意味着当前容器中只有一个ConfigurationClassPostProcessor会被执行,在前文中我们已经分析过了它
的postProcessBeanDefinitionRegistry方法,紧接着我们就来看看它的postProcessBeanFactory方法做了什么。其源码如下:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
// 防止重复处理
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
// 在执行postProcessBeanDefinitionRegistry方法的时就已经将这个id添加到registriesPostProcessed集合中了
if (!this.registriesPostProcessed.contains(factoryId)) {
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 看起来这个方法就是完成了代理
enhanceConfigurationClasses(beanFactory);
// 添加了一个后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
enhanceConfigurationClasses源码分析
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) { // map中放置的是所有需要被代理的类
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
// 省略异常跟日志代码....
// 这个代码的含义就是如果是一个被@Configuration注解标注的类,那么将其放入到configBeanDefs这个集合中
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}

















安全验证
文档复制为VIP权益,开通VIP直接复制

评论0