@Configuration源码讲解

示例

// ------------------------ 配置文件
@Configuration
public class SpringConfig {
    @Bean
    public Piano piano() {
        return new Piano();
    }

    @Bean(name = "counter")
    public Counter counter() {
        return new Counter(12, "Shake it Off", piano());
    }
}

// ------------------------ 测试

ApplicationContext annotationContext = new AnnotationConfigApplicationContext("xxxPackagePath");
Counter c = annotationContext.getBean("counter", Counter.class);
Assert.assertEquals("糊涂",c.getName()); //测试

AnnotationConfigApplicationContext

以上的代码非常简单, 一眼就能看出关键点就是这个AnnotationConfigApplicationContext类了.

而下面的AnnotationConfigApplicationContext构造函数中, 相信注释已经很清楚了, 这里我们关注的重点当然就是scan(basePackages);方法.至于其它两个方法:

  1. this(); 主要是为了实例化自身的两个重要字段.

  2. refresh(); 这个方法至关重要, 不过不是本文的重点. 所以直接略过.如果读者有兴趣, 可以参见本人下面给出的链接, 或者查阅《Spring源码深度解读》—— 作者在其书中对此方法进行了详尽的解读, 个人觉得还是很值得买一本的

  • AnnotationConfigApplicationContext.scan 方法

  • ClassPathBeanDefinitionScanner.scan 方法

  • AnnotationConfigUtils.registerAnnotationConfigProcessors 方法

  • ConfigurationClassPostProcessor类

既然此次我们关注的重点是@Configuration, 目光当然就落在ConfigurationClassPostProcessor类上了, 观察其继承链, 鼎鼎大名的BeanFactoryPostProcessor赫然在目. 这个类的关键性就不在这里赘述了.

ConfigurationClassPostProcessor 继承链

所以Spring会回调这两个方法

  1. postProcessBeanDefinitionRegistry(由BeanDefinitionRegistryPostProcessor接口定义)

  2. postProcessBeanFactory(由BeanFactoryPostProcessor接口定义)

  3. BeanDefinitionRegistryPostProcessor接口又继承自BeanFactoryPostProcessor; 依据注释, 前者所定义方法的被执行时机位于后者所定义方法之前.

通过观察上面必将被Spring框架回调的两个方法, 我们可以推测:

  1. 这两个方法必将被会调用, 且都只会被调用一次.

  2. 在执行顺序是 processConfigBeanDefinitions在先, 而enhanceConfigurationClasses在后.

  3. processConfigBeanDefinitions方法

  • ConfigurationClassParser类

Parse each @Configuration class — 官方注释

访问级别级别为 package;

位于org.springframework.context.annotation package下

  • ConfigurationClassBeanDefinitionReader类

这个类的访问级别也是 package.

  • enhanceConfigurationClasses方法

唯一想要提及的是 如果我们从容器中取出配置类(例如通过springConfig作为key取出上面的定义的SpringConfig)的话, 就会发现, Spring返回给我们的并不是一个原生的SpringConfig实例; 而是类似SpringConfigEnhancerBySpringCGLIBEnhancerBySpringCGLIB47a5de53@11935e这样的实例; 这明显就是被CGLIB代理过的.

而原因就发生在 ConfigurationClassPostProcessor类的enhanceConfigurationClasses方法中.

其它暂时略.

Last updated

Was this helpful?