文章目录
前情
哎,感觉挤出来的时间仍旧不够用,前天的文章写到深夜一点了,很想定期(原计划每天,感觉不太现实)发一篇高质量的源码解析的博文。
个人的源码解析思路是想从spring核心源码解析作为起点,后续陆续分析mybatis、spring boot 、dubbo源码,这些也都是本人接触并深入过的框架(至于spring cloud全家桶,项目中用过,但并没有深入),感觉还挺有挑战的,希望自己能坚持下去。
本文主要是以@Configuration注解标注的bean是如何实例化的,它和@Component注解又有什么区别?以及简单的扩展,@Configuration注解是spring 以及spring boot 注解驱动中非常核心重要的,掌握它是非常有必要的。
1. @Configuration配置类的实例化的流程分析
spring内置的很多注解,如@Autowired、@Import、@Configuration、包括aop动态代理等等,都是通过内置的后置处理器进行处理的。
这次讲的@Configuration注解的核心处理类也是一个后置处理器ConfigurationClassPostProcessor,后文将重点讲解。
在第一篇spring核心之概况流程 的文章里的刷新上下文refresh方法中的 —>调用 beanFactoryPostProcessors beanFactory的后置处理器中就开始如下UML图的中的调用链,有兴趣的小伙伴可以跟踪一下源码,下面来一起看看几个很关键的方法源码。(本人跟踪源码所画)
2. ConfigurationClassPostProcessor后置处理器
这个方法是对应在上图中的第三步骤,核心的第一个后置处理在processConfigBeanDefinitions(registry);方法中,这个方法很长,请耐心看下去,该方法中我标记了三个重点,并从这三点进行分别讲解。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
//处理配置类的bean定义
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//full模式的配置类,会在postProcessBeanFactory方法中做CGLIB动态代理来增强类
//重点1 :检查beanDef是不是一个加了@Configuration(full) 或者(lite)加了Component、ComponentScan、Import、ImportResource注解,如果是有配置类,则加入到configCandidates数组中
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
//配置类的解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory