ConfigurationClassPostProcessor类继承体系
ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor ,BeanFactoryPostProcessor接口。
添加到容器后,Spring容器refresh过程中会调用容器后处理器Ben处理BeanDefinition中beanClass有@Configuration
注解的bean(相当于一个xml文件),从而导入其它bean
我们来看下例子
public class AnnotationConfigApplicationContextTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader((BeanDefinitionRegistry) context);
reader.register(AppConfig.class);
context.refresh();
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName:beanNames ) {
System.err.println(beanName);
}
}
}
@Configuration
public class AppConfig {
@Bean(name="demoBean")
public DemoBean bean1() {
DemoBean demoBean = new DemoBean();
demoBean.setName("bean1");
return demoBean;
}
@Bean
public DemoBean bean2() {
DemoBean demoBean = new DemoBean();
demoBean.setName("bean2");
return demoBean;
}
@Configuration(proxyBeanMethods = false)
protected static class InnerBean {
@Bean
public DemoBean bean() {
DemoBean demoBean = new DemoBean();
demoBean.setName("bean3");
return demoBean;
}
}
}
public class DemoBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
打印结果,处理容器添加的几个Bean,还有register注册的AppConfig,另外还有demoBean bean2两个bean,这就是ConfigurationClassPostProcessor 的作用了,对于@Configuration修饰的类如果类的方法是有@Bean注解修饰包装成一个Bean,
当然不止这些,@Configuration相当于我们用xml配置文件 ,接下来我们详细了解ConfigurationClassPostProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig
demoBean
bean2
postProcessBeanDefinitionRegistry
容器refresh过程中先调用postProcessBeanDefinitionRegistry方法(BeanDefinitionRegistryPostProcessor 接口),这里面先做校验判断有没有调用过然后再调用processConfigBeanDefinitions(registry)
方法,这里是解析Configuration
配置类的入口
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);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 筛选出 有Configuration 注解(包含有Import 其它关联的注解的类)
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, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
/**
* @Configuration 注解类包装而成的
*/
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// Map<ConfigurationClass, ConfigurationClass> configurationClasses ConfigurationClassParser内部持有这个属性
parser.parse(candidates);
parser.validate();
// parser.parse(candidates) 会在parser解析器类中生成一组ConfigurationClass对象 分析@Configuration注解的配置类 产生一组ConfigurationClass对象
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
/**
* 解析配置前容器中的Bean
*/
if (registry.getBeanDefinitionCount() > candidateNames.length) {
/**
* ConfigurationClass 解析后容器中的bean
*/
String[] newCandidateNames = registry.getBeanDefinitionNames();
/**
* 解析前容器中的Bean
*/
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
/**
* 已经解析过的ConfigurationClass配置类
*/
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
/**
* 下一轮循环继续处理
*/
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
/**
* candidates 为空时处理结束
*/
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
代码比较长,主要流程如下图
大概分析下这里的逻辑
- 容器中筛选出Configuration配置类的Bean并排序
第2-17行从容器中拿到ConfigurationClassPostProcessor可以解析的Bean也就是有Configuration
注解的Bean - 创建一个构造ConfigurationClassParser
50-52行创建了一个ConfigurationClassParser这个用来解析上面拿到的Configuration配置类,调用parse方法解析后会生成一组 ConfigurationClass类 - 56-57 行创建两个Set容器(
candidates alreadyParsed
)分别存Spring容器中的Configuration
配置类,和经过 ConfigurationClassParser解析生成的ConfigurationClass
类,candidates 会在解析ConfigurationClass后删除,下一轮如果重新生成了可以解析的配置类继续放在这个Set里面
可以看到58-113行是一个循环,这样处理是因为Configuration配置类解析后可能还需要解析 - 调用ConfigurationClassParser 解析candidates 生成ConfigurationClass(这个也比较重要,我们后面在看)
- 第67-72行 创建ConfigurationClassBeanDefinitionReader 来处理ConfigurationClassParser解析candidates 生成的ConfigurationClass,往Spring容器中注册Bean,在这之前会64行会将之前已经解析过的
ConfigurationClass
剔除掉 - 75行将这一类的Configuration配置类删除(已经解析过了 防止while循环重复解析)
- 第79至107行判断解析ConfigurationClass后容器中有没有多出Bean ,如果多出来看是否是
Configuration配置类再次解析
- 第116-118行往容器里面注入了一个单例Bean 实例时ConfigurationClassParser解析生成的ImportRegistry对象
这里在哪里用到呢
在postProcessBeanFactory
方法(这个也是容器后处理器Bean的接口方法在Refresh过程中也会调用)后面添加了一个ImportAwareBeanPostProcessor
后处理器,postProcessBeforeInitialization
对Bean增强处理的时候用到
这里是processConfigBeanDefinitions
的外层逻辑,整个流程中还有两个比较重要的点
- ConfigurationClassParser 怎样将
Configuration
配置类解析成ConfigurationClass
- ConfigurationClassBeanDefinitionReader 怎样解析
ConfigurationClass
并注册Bean到Spring容器
解析来我们来了解这两点
ConfigurationClassParser 解析Configuration
配置类
ConfigurationClassParser 类的内部属性
属性 | 描述 |
---|---|
MetadataReaderFactory metadataReaderFactory | 可以读取类的元数据,注解元素据信息 |
BeanDefinitionRegistry registry | 也就是当前Spring容器 |
ComponentScanAnnotationParser componentScanParser | 解析ComponentScans注解信息导入Bean ,等同于处理 xml component-scan 标签 |
ConditionEvaluator conditionEvaluator | 判断当前Configuration配置类是否可以注册到容器SpringBoot SpringCloud项目中一般都有@Conditional条件注解进一步判断是否可以导入 |
Map<ConfigurationClass, ConfigurationClass> configurationClasses | 一个Configuration注解就会被解析成ConfigurationClass |
ist propertySourceNames | 保存PropertySources 注解的name |
ImportStack importStack | 当前配置类有内部类或者有Import注解时,当前配置类添加到这个ImportStack ,前面说到添加了一个ImportAwareBeanPostProcessor 后处理器,postProcessBeforeInitialization 对Bean增强处理的时候用到一个单例Bean,这个Bean存的就是ImportStack 对象 |
deferredImportSelectorHandler | Import注解导入的类实现了DeferredImportSelector接口添加到这个容器里面 |
parse方法
针对传入的Configuration
配置类集合按照Bean类型有不同的处理方式,最后调用到的都是同一个processConfigurationClass
方法,然后解析完所有配置类后调用this.deferredImportSelectorHandler.process()
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
这里猜测在调用parse方法后往deferredImportSelectors
对象里面存值了,我们先看看parse方法
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
/**
* 如果这里shouldSkip返回true 就不做进一步处理
*/
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
在前面分析processConfigBeanDefinitions
方法时有提到ConfigurationClassBeanDefinitionReader 拿到ConfigurationClassParser
解析生成的ConfigurationClass,processConfigurationClass
方法就做到了这点
我们先看看ConfigurationClass 有哪些属性
属性 | 描述 |
---|---|
AnnotationMetadata metadata | 注解元数据 |
Set importedBy | 不为空的化 代表这个类是因为其它类的注解引入的 |
Set beanMethods | @Bean注解修饰的方法 |
importedResources | 处理ImportResource 注解,相当于xml中的 import 其它bean配置文件标签,定义了BeanDefinitionReader |
importBeanDefinitionRegistrars | @Import 注解导入的Bean如果继承了ImportBeanDefinitionRegistrar接口添加到这 |
上面的代码我们先看下这个do while循环,同样的套路在doProcessConfigurationClass
方法里面又有可能新生成SourceClass
类
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
/**
* 等同于处理 xml component-scan 标签
*/
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
// getImport 处理import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
/**
* ImportResource 相当于xml中的 import 其它bean配置文件标签
*/
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
主要有这几块逻辑,涵盖了Configuration
配置类的所有操作
第76到78行就是看看传入的配置类有没有父类,如果有就继续解析父类
我们再具体了解下doProcessConfigurationClass
的处理过程
1处理内部类
AppConfig有一个内部类InnerBean
也有一个Configuration
注解修饰会重新当做一个ConfigurationClass
调用doProcessConfigurationClass
方法解析
ConfigurationClassParser
解析器processMemberClasses
方法处理当前配置类的内部类
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
Predicate<String> filter) throws IOException {
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
this.importStack.pop();
}
}
}
}
}
判断内部类是否是可以处理的Configuration
配置类,如果是重新调用processConfigurationClass
解析
2 解析PropertySources注解
3 处理ComponentScans ComponentScans注解
这个注解的作用等同于 component-scan
标签,起到扫描指定包路径注册Bean到容器里面的功能
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
第3到4行是判断条件存在ComponentScans ComponentScans注解并且满足条件注解
第7到8行调用到ClassPathBeanDefinitionScanner
doScan方法注册Bean到容器
第15 16行是判断扫描到的Bean是否是Configuration
配置类,如果是的话继续调用ConfigurationClassParser
解析
4 处理Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
里面有个getImports
方法 这个就是收集Configuration
配置类里面Import注解导入的类
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<>();
Set<SourceClass> visited = new LinkedHashSet<>();
collectImports(sourceClass, imports, visited);
return imports;
}
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
collectImports方法里面第4到10行就是遍历Configuration
配置类除Import
外的所有注解信息,
11行就是获取当前配置类Import注解的 value属性,也就是导入的值
之所以要有7-9行的逻辑是,是因为Configuration
配置类上的其它注解可能也通过Import导入了一些类,所以再执行一遍collectImports
方法
接下来再看看processImports
方法,这里就是针对Import
注解导入的类怎么处理了
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
第9到11行是判断是否有循环导入的情况 ,后面的for循环就是针对不同的导入类做处理了
主要分三种情况
-
导入的类是ImportSelector实现类
这里分两种情况如果也实现了DeferredImportSelector
接口调用DeferredImportSelectorHandler
Handler方法,
对于这个handler方法往内部类DeferredImportSelectorHandler
的deferredImportSelectors
属性添加了一个值,我们前面提到在parse方法处理
BeanDefinitionHolder
集合的逻辑里面,最后面调用了this.deferredImportSelectorHandler.process()
Spring Boot的AutoConfigurationImportSelector
就实现了DeferredImportSelector这个接口
如果只实现了
ImportSelector
接口,这个接口提供了selectImports方法返回一组要导入的类,这种场景拿到导入的类再执行下 processImports方法就走到下面第三种情况了 -
导入的类是ImportBeanDefinitionRegistrar接口实现类
这种情况往ConfigurationClass
的importBeanDefinitionRegistrars
Map里添加了一条数据 key 是ImportBeanDefinitionRegistrar
实现类,ImportBeanDefinitionRegistrar
接口提供了一个方法往容器中注册Bean,可以猜测下ConfigurationClassBeanDefinitionReader
解析怎样ConfigurationClass类了
3. 以上两种情况都不是 就再调用一次processConfigurationClass 来解析这个类
5处理ImportResource注解
将注解对应的资源添加到 importedResources
属性
6处理方法上的@Bean注解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
筛选出Bean
注解修饰的方法包装成MethodMetadata Set 添加到beanMethods
属性中,具体实现在retrieveBeanMethodMetadata方法中
7处理接口方法
JAVA 8 后接口也有默认方法,也是调用retrieveBeanMethodMetadata
方法获取Bean
注解修饰的的方法
ConfigurationClassBeanDefinitionReader 怎样解析ConfigurationClass往容器中注册Bean
在解析完Configuration
配置类生成ConfigurationClass
并将注解导入的相关属性配置添加到ConfigurationClass变量后,接下来就是ConfigurationClassBeanDefinitionReader
解析 ConfigurationClass往容器里面注册bean的流程
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
/**
* 导入的其它资源文件解析bean
*/
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
/**
* 注册实现了ImportBeanDefinitionRegistrar接口bean
*/
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
这里面分四种情况向容器中注册Bean
postProcessBeanFactory方法
在完成postProcessBeanDefinitionRegistry方法后,接下来就是处理BeanFactoryPostProcessor的回调方法
这个回调方法主要做了两个事情
- 对应CONFIGURATION_CLASS_FULL模式的配置类,通过Cglib创建一个代理类(BeanMethodInterceptor BeanFactoryAwareMethodInterceptor两个回调函数),作为这个配置类bean的beanClass属性值
- 添加一个Bean后处理器 ImportAwareBeanPostProcessor
总结
这里主要分析了下ConfigurationClassPostProcessor 处理Configuration
配置类到注册Bean的流程,
大致分两个个模块
ConfigurationClassParser
解析器怎样解析Configuration
配置类构造ConfigurationClass对象ConfigurationClassBeanDefinitionReader
怎样解析ConfigurationClass 注册BeanDefinition 到容器
受限于个人知识水平,有些流程细节部分未深入了解,如有错误之处欢迎指出