ConfigurationClassPostProcessor原理浅析

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();
		}
	}

代码比较长,主要流程如下图
在这里插入图片描述

大概分析下这里的逻辑

  1. 容器中筛选出Configuration配置类的Bean并排序
    第2-17行从容器中拿到ConfigurationClassPostProcessor可以解析的Bean也就是有Configuration注解的Bean
  2. 创建一个构造ConfigurationClassParser
    50-52行创建了一个ConfigurationClassParser这个用来解析上面拿到的Configuration配置类,调用parse方法解析后会生成一组 ConfigurationClass类
  3. 56-57 行创建两个Set容器(candidates alreadyParsed)分别存Spring容器中的Configuration配置类,和经过 ConfigurationClassParser解析生成的ConfigurationClass类,candidates 会在解析ConfigurationClass后删除,下一轮如果重新生成了可以解析的配置类继续放在这个Set里面
    可以看到58-113行是一个循环,这样处理是因为Configuration配置类解析后可能还需要解析
  4. 调用ConfigurationClassParser 解析candidates 生成ConfigurationClass(这个也比较重要,我们后面在看)
  5. 第67-72行 创建ConfigurationClassBeanDefinitionReader 来处理ConfigurationClassParser解析candidates 生成的ConfigurationClass,往Spring容器中注册Bean,在这之前会64行会将之前已经解析过的ConfigurationClass剔除掉
  6. 75行将这一类的Configuration配置类删除(已经解析过了 防止while循环重复解析)
  7. 第79至107行判断解析ConfigurationClass后容器中有没有多出Bean ,如果多出来看是否是Configuration配置类再次解析
  8. 第116-118行往容器里面注入了一个单例Bean 实例时ConfigurationClassParser解析生成的ImportRegistry对象
    这里在哪里用到呢
    postProcessBeanFactory方法(这个也是容器后处理器Bean的接口方法在Refresh过程中也会调用)后面添加了一个ImportAwareBeanPostProcessor后处理器,postProcessBeforeInitialization对Bean增强处理的时候用到

这里是processConfigBeanDefinitions的外层逻辑,整个流程中还有两个比较重要的点

  1. ConfigurationClassParser 怎样将Configuration配置类解析成ConfigurationClass
  2. 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 对象
deferredImportSelectorHandlerImport注解导入的类实现了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行调用到ClassPathBeanDefinitionScannerdoScan方法注册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循环就是针对不同的导入类做处理了

主要分三种情况

  1. 导入的类是ImportSelector实现类
    这里分两种情况如果也实现了DeferredImportSelector接口调用DeferredImportSelectorHandlerHandler方法,
    对于这个handler方法往内部类DeferredImportSelectorHandlerdeferredImportSelectors属性添加了一个值,

    我们前面提到在parse方法处理BeanDefinitionHolder集合的逻辑里面,最后面调用了this.deferredImportSelectorHandler.process()
    Spring Boot的AutoConfigurationImportSelector 就实现了DeferredImportSelector这个接口
    在这里插入图片描述

    如果只实现了ImportSelector接口,这个接口提供了selectImports方法返回一组要导入的类,这种场景拿到导入的类再执行下 processImports方法就走到下面第三种情况了

  2. 导入的类是ImportBeanDefinitionRegistrar接口实现类
    这种情况往ConfigurationClassimportBeanDefinitionRegistrarsMap里添加了一条数据 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的回调方法

这个回调方法主要做了两个事情

  1. 对应CONFIGURATION_CLASS_FULL模式的配置类,通过Cglib创建一个代理类(BeanMethodInterceptor BeanFactoryAwareMethodInterceptor两个回调函数),作为这个配置类bean的beanClass属性值
  2. 添加一个Bean后处理器 ImportAwareBeanPostProcessor

总结

这里主要分析了下ConfigurationClassPostProcessor 处理Configuration配置类到注册Bean的流程,
大致分两个个模块

  1. ConfigurationClassParser 解析器怎样解析Configuration配置类构造ConfigurationClass对象
  2. ConfigurationClassBeanDefinitionReader 怎样解析ConfigurationClass 注册BeanDefinition 到容器

受限于个人知识水平,有些流程细节部分未深入了解,如有错误之处欢迎指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值