SpringBoot 注解 @Import 的原理-ConfigurationClassPostProcessor 源码解析

1. @Import 介绍

1.1 @Import 的作用

Spring 中将一个普通类交给容器管理除了使用 @Bean@Component等注解再使用 @ComponentScan 扫描包之外,还可以使用 @Import 注解

@Import只能用在类或者其他注解上 ,该注解能够方便快速地实现把实例加入到 Spring 的 IOC 容器中,可用于导入第三方包

1.2 @Import 的使用方式

@Import 可以快速导入目标类,其主要有以下几种用法:

  1. 直接填写 class 数组,导入目标类
  2. 导入实现 ImportSelector 接口的类
  3. 导入实现 ImportBeanDefinitionRegistrar 接口的类

1.2.1 直接导入目标类

这种方式直接在@Import中指定 class 数组,Spring 会在启动过程把 @Import 中配置的 bean 直接导入到 Spring 容器中,其 beanName 为类的全限定名,使用方法如下:

@Import({
    
     abc.class , abd.class... })
public class Config {
    
    
}

1.2.2 导入实现 ImportSelector 接口的类

ImportSelector是一个导入的选择器,可以通过这个接口的实现决定引入哪些配置。以 @EnableAsync上通过@Import导入的 AsyncConfigurationSelector 为例,Spring 容器会在启动过程中实例化该选择器并调用其selectImports()方法。 AsyncConfigurationSelector#selectImports() 根据 @EnableAsync 中指定的模式选择对应的配置类,默认代理模式,则导入指定的 ProxyAsyncConfiguration配置类

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
    
    

	private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
			
	@Override
	@Nullable
	public String[] selectImports(AdviceMode adviceMode) {
    
    
		switch (adviceMode) {
    
    
			case PROXY:
				return new String[] {
    
    ProxyAsyncConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {
    
    ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}

}

1.2.3 导入实现 ImportBeanDefinitionRegistrar 接口的类

ImportBeanDefinitionRegistrar 是一个 bean 定义注册器,以 @EnableAspectJAutoProxy注解通过 @Import(AspectJAutoProxyRegistrar.class) 引入了注册类 AspectJAutoProxyRegistrar 为例,在框架启动过程中会回调其实现的接口方法 AspectJAutoProxyRegistrar#registerBeanDefinitions()方法将目标 bean 注册到容器中

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
    

	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
    

		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
    
    
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
    
    
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
    
    
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

2. @Import 注册目标类的流程

以下流程图以 @EnableAsync 注解使用 @Import 导入 AsyncConfigurationSelector 为例子,全流程展现了@Import 导入的类被解析为 BeanDefinition 并注册到 Spring 容器中过程,以及 @Async注解核心原理。 简单来说,整个过程总共分为以下几步:

  1. 配置解析类ConfigurationClassPostProcessor的注册
  2. ConfigurationClassPostProcessor 解析配置类,并将其注册到容器
  3. BeanPostProcessor 后置处理器对象的优先创建
  4. @Async 异步任务代理对象的生成及其生效原理

在这里插入图片描述

2.1 配置解析类 ConfigurationClassPostProcessor 的注册

  1. SpringApplication#run() 方法为框架启动的入口,启动过程中 prepareContext() 方法会为 Context 准备必要的组件,其中就包括 ConfigurationClassPostProcessor 的注册

    public ConfigurableApplicationContext run(String... args) {
          
          
     	
     	......
     	
     	try {
          
          
     		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
     				args);
     		ConfigurableEnvironment environment = prepareEnvironment(listeners,
     				applicationArguments);
     		configureIgnoreBeanInfo(environment);
     		Banner printedBanner = printBanner(environment);
     		context = createApplicationContext();
     		exceptionReporters = getSpringFactoriesInstances(
     				SpringBootExceptionReporter.class,
     				new Class[] {
          
           ConfigurableApplicationContext.class }, context);
     		prepareContext(context, environment, listeners, applicationArguments,
     				printedBanner);
     		refreshContext(context);
     		afterRefresh(context, applicationArguments);
     		stopWatch.stop();
     		
     	......
     	
     	return context;
     }
    
  2. SpringApplication#prepareContext() 中会调用 SpringApplication#load() 将必要的组件加载进容器中,以下为 load() 方法实现,可以看到方法内部调用了 createBeanDefinitionLoader() 方法

    protected void load(ApplicationContext context, Object[] sources) {
          
          
     	if (logger.isDebugEnabled()) {
          
          
     		logger.debug(
     				"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
     	}
     	BeanDefinitionLoader loader = createBeanDefinitionLoader(
     			getBeanDefinitionRegistry(context), sources);
     	if (this.beanNameGenerator != null) {
          
          
     		loader.setBeanNameGenerator(this.beanNameGenerator);
     	}
     	if (this.resourceLoader != null) {
          
          
     		loader.setResourceLoader(this.resourceLoader);
     	}
     	if (this.environment != null) {
          
          
     		loader.setEnvironment(this.environment);
     	}
     	loader.load();
     }
    
  3. SpringApplication#createBeanDefinitionLoader() 会创建 BeanDefinition 的加载器,最终创建的对象为 BeanDefinitionLoader

    protected BeanDefinitionLoader createBeanDefinitionLoader(
    		BeanDefinitionRegistry registry, Object[] sources) {
          
          
    	return new BeanDefinitionLoader(registry, sources);
    }
    
  4. BeanDefinitionLoader 的构造方法中会初始化一系列的组件,其中包括了 AnnotatedBeanDefinitionReader

    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
          
          
     	Assert.notNull(registry, "Registry must not be null");
     	Assert.notEmpty(sources, "Sources must not be empty");
     	this.sources = sources;
     	this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
     	this.xmlReader = new XmlBeanDefinitionReader(registry);
     	if (isGroovyPresent()) {
          
          
     		this.groovyReader = new GroovyBeanDefinitionReader(registry);
     	}
     	this.scanner = new ClassPathBeanDefinitionScanner(registry);
     	this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
     }
    
  5. AnnotatedBeanDefinitionReader 的构造方法会通过工具类AnnotationConfigUtils#registerAnnotationConfigProcessors()注册注解配置的处理器

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
          
          
     	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
     	Assert.notNull(environment, "Environment must not be null");
     	this.registry = registry;
     	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
     	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
     }
    
  6. AnnotationConfigUtils#registerAnnotationConfigProcessors() 方法会注册许多 Spring 必须的处理器,本文主要关注 ConfigurationClassPostProcessor 这个配置类的后置处理器,可以看到此时已经将其包装到 BeanDefinition中了

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
     		BeanDefinitionRegistry registry, @Nullable Object source) {
          
          
        ......
    
     	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    
     	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
          
          
     		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
     		def.setSource(source);
     		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
     	}
        ......
    
     	return beanDefs;
     }
    

2.2 ConfigurationClassPostProcessor 解析配置类

  1. Context 准备完毕,会调用 SpringAppliction#refreshContext() 方法,最终调用到著名的 AbstractApplicationContext#refresh() 方法。该方法体内各个方法的作用可参考 Spring 启动流程源码解析,本文主要关注 invokeBeanFactoryPostProcessors()方法

    public void refresh() throws BeansException, IllegalStateException {
          
          
     	synchronized (this.startupShutdownMonitor) {
          
          
     		// Prepare this context for refreshing.
     		prepareRefresh();
    
     		// Tell the subclass to refresh the internal bean factory.
     		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
     		// Prepare the bean factory for use in this context.
     		prepareBeanFactory(beanFactory);
    
     		try {
          
          
     			// Allows post-processing of the bean factory in context subclasses.
     			postProcessBeanFactory(beanFactory);
    
     			// Invoke factory processors registered as beans in the context.
     			invokeBeanFactoryPostProcessors(beanFactory);
    
     			// Register bean processors that intercept bean creation.
     			registerBeanPostProcessors(beanFactory);
    
     			// Initialize message source for this context.
     			initMessageSource();
    
     			// Initialize event multicaster for this context.
     			initApplicationEventMulticaster();
    
     			// Initialize other special beans in specific context subclasses.
     			onRefresh();
    
     			// Check for listener beans and register them.
     			registerListeners();
    
     			// Instantiate all remaining (non-lazy-init) singletons.
     			finishBeanFactoryInitialization(beanFactory);
    
     			// Last step: publish corresponding event.
     			finishRefresh();
     		}
    
     		......
     	}
     }
    
  2. AbstractApplicationContext#invokeBeanFactoryPostProcessors()方法会调用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 方法,这个方法的源码如下,可以看到其主要做了以下几件事:

    1. 从 bean 工厂中获取所有实现 BeanFactoryPostProcessor 接口的 bean 名称
    2. 通过 beanFactory.getBean() 去创建注册到容器中的 BeanFactoryPostProcessor 实例
    3. 通过 invokeBeanFactoryPostProcessors() 方法调用 BeanFactoryPostProcessor 接口方法
    public static void invokeBeanFactoryPostProcessors(
     		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
          
          
         
         ......
     	
     	// Do not initialize FactoryBeans here: We need to leave all regular beans
     	// uninitialized to let the bean factory post-processors apply to them!
     	String[] postProcessorNames =
     			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    
     	// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
     	// Ordered, and the rest.
     	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
     	List<String> orderedPostProcessorNames = new ArrayList<>();
     	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
     	for (String ppName : postProcessorNames) {
          
          
     		if (processedBeans.contains(ppName)) {
          
          
     			// skip - already processed in first phase above
     		}
     		else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
          
          
     			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
     		}
     		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
          
          
     			orderedPostProcessorNames.add(ppName);
     		}
     		else {
          
          
     			nonOrderedPostProcessorNames.add(ppName);
     		}
     	}
    
     	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
     	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
     	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    
     	// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
     	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
     	for (String postProcessorName : orderedPostProcessorNames) {
          
          
     		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
     	}
     	sortPostProcessors(orderedPostProcessors, beanFactory);
     	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    
     	// Finally, invoke all other BeanFactoryPostProcessors.
     	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
     	for (String postProcessorName : nonOrderedPostProcessorNames) {
          
          
     		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
     	}
     	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    
     	// Clear cached merged bean definitions since the post-processors might have
     	// modified the original metadata, e.g. replacing placeholders in values...
     	beanFactory.clearMetadataCache();
     }
    
  3. ConfigurationClassPostProcessor 已经完成注册,且实现了 BeanFactoryPostProcessor 接口,则经过步骤 2 ConfigurationClassPostProcessor#postProcessBeanFactory() 方法将被调用,可以看到方法内部核心其实是ConfigurationClassPostProcessor#processConfigBeanDefinitions() 方法

    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);
     	if (!this.registriesPostProcessed.contains(factoryId)) {
          
          
     		// BeanDefinitionRegistryPostProcessor hook apparently not supported...
     		// Simply call processConfigurationClasses lazily at this point then.
     		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
     	}
    
     	enhanceConfigurationClasses(beanFactory);
     	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
     }
    
  4. ConfigurationClassPostProcessor#processConfigBeanDefinitions() 方法,其内部比较重要的步骤如下:

    1. 生成 ConfigurationClassParser 对象并调用其 parse() 方法用于解析配置类,缓存其配置的 Bean
    2. 使用 ConfigurationClassBeanDefinitionReader 对象调用其 loadBeanDefinitions() 将配置类中的 Bean 注册到容器中
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
          
          
    
     	......
     	
     	// Parse each @Configuration class
     	ConfigurationClassParser parser = new ConfigurationClassParser(
     			this.metadataReaderFactory, this.problemReporter, this.environment,
     			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
     	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
     	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
     	do {
          
          
     		parser.parse(candidates);
     		parser.validate();
    
     		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();
     		if (registry.getBeanDefinitionCount() > candidateNames.length) {
          
          
     			String[] newCandidateNames = registry.getBeanDefinitionNames();
     			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
     			Set<String> alreadyParsedClasses = new HashSet<>();
     			for (ConfigurationClass configurationClass : alreadyParsed) {
          
          
     				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;
     		}
     	}
     	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();
     	}
     }
    
  5. ConfigurationClassParser#parse() 方法是解析配置类的核心入口,其最终调用到了 ConfigurationClassParser#processConfigurationClass()方法。这个方法主要处理逻辑是调用 doProcessConfigurationClass()解析配置类,并将解析得到的 Bean 缓存在 Map 集合 configurationClasses 中供后续注册使用

    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
          
          
     	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);
     	do {
          
          
     		sourceClass = doProcessConfigurationClass(configClass, sourceClass);
     	}
     	while (sourceClass != null);
    
     	this.configurationClasses.put(configClass, configClass);
     }
    
  6. ConfigurationClassParser#doProcessConfigurationClass() 是解析配置的核心方法,其主要的处理步骤如下,本文主要关注 processImports() 处理 @Import 注解引入 Bean 的流程

    1. processMemberClasses() 处理内部类
    2. processPropertySource() 处理加了@PropertySource 注解的属性资源文件
    3. 解析出类上的@ComponentScan和@ComponentScans注解,然后根据其配置包路径扫描出所有需要交给Spring管理的类,因为扫描出的类中可能也被加了@ComponentScan和@ComponentScans注解,因此需进行递归解析,直到所有标注了这两个注解的类被解析完毕
    4. processImports() 处理通过 @Import注解配置的 Bean
    5. 处理 @ImportResource 注解标注的配置文件
    6. doProcessConfigurationClass() 会被递归调用,则最终会处理配置类中加了@Bean 注解的方法
    7. processInterfaces() 处理接口的默认方法。从JDK8开始,接口中的方法可以有自己的默认实现如果这个接口中的方法也加了@Bean注解,也需要被解析
    8. 解析父类,如果被解析的配置类继承了某个类,那么配置类的父类也会被进行解析(父类是全类名以 java 开头的JDK内置的类例外)
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
     		throws IOException {
          
          
    
     	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
          
          
     		// Recursively process any member (nested) classes first
     		processMemberClasses(configClass, sourceClass);
     	}
    
     	// 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
     	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
     	processImports(configClass, sourceClass, getImports(sourceClass), true);
    
     	// 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;
     }
    
  7. ConfigurationClassParser#processImports() 方法主要处理 3 种类型的 Bean:

    1. ImportSelector.class 接口的实现
      实例化这个类的对象,然后调用其 selectImports() 方法去获得所需要的引入的配置类, 然后调用 processImports() 递归处理
    2. ImportBeanDefinitionRegistrar 接口的实现
      实例化这个类的对象,将其添加到缓存到 Map 集合中
    3. 普通类
      把它当作 @Configuration 标注的类调用最外层的processConfigurationClass()继续处理
    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
     		Collection<SourceClass> importCandidates, 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 = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
     					ParserStrategyUtils.invokeAwareMethods(
     							selector, this.environment, this.resourceLoader, this.registry);
     					if (selector instanceof DeferredImportSelector) {
          
          
     						this.deferredImportSelectorHandler.handle(
     								configClass, (DeferredImportSelector) selector);
     					}
     					else {
          
          
     						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
     						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
     						processImports(configClass, currentSourceClass, importSourceClasses, 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 =
     							BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
     					ParserStrategyUtils.invokeAwareMethods(
     							registrar, 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));
     				}
     			}
     		}
     		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();
     		}
     	}
     }
    
  8. 经过步骤5-7处理,引入的类都被解析完毕,接下来则会调用 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions() 将配置类中的解析出来的 Bean 注册到容器中

    从代码来看,其实主要是 loadBeanDefinitionsForConfigurationClass() 方法完成注册工作,这里主要把需要注册的类分为了 4 类。通过这个步骤,@EnableAsync 注解上经 @Import 导入的 AsyncConfigurationSelector 选择器选中的配置类 ProxyAsyncConfiguration 注册到了容器中,并且这个配置类内部配置的 AsyncAnnotationBeanPostProcessor 也注册到了容器中

    1. 被 @Configuration 标注的配置类或者 @Import 导入的普通类
    2. 被 @Bean 标注的方法配置的类
    3. 被 @ImportResource 导入的类
    4. 被 @Import 导入的 ImportBeanDefinitionRegistrar 接口实现类
    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
          
          
     	TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
     	for (ConfigurationClass configClass : configurationModel) {
          
          
     		loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
     	}
     }
    
     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);
     	}
    
     	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
     	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
     }
    

2.3 BeanPostProcessor 后置处理器对象的优先创建

  1. 容器启动过程中AbstractApplicationContext#invokeBeanFactoryPostProcessors() 准备 Bean 工厂的后置处理器完毕,就需要调用 AbstractApplicationContext#registerBeanPostProcessors() 将 Bean 的后置处理器注册到容器中了。这个过程通过 PostProcessorRegistrationDelegate.registerBeanPostProcessors() 方法完成,其流程与 Bean 工厂后置处理器的注册大致相同:

    1. 首先 beanFactory.getBeanNamesForType() 获取所有实现 BeanPostProcessor 接口的类名数组
    2. beanFactory.getBean() 创建 BeanPostProcessor 实例
    3. registerBeanPostProcessors() 将 BeanPostProcessor 实例保存下来,在创建 Bean 的时候根据匹配规则确定某个 BeanPostProcessor 是否需应用于创建 Bean 代理对象
    public static void registerBeanPostProcessors(
     		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
          
          
    
     	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
         
         ......
     	
     	// Now, register all regular BeanPostProcessors.
     	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
     	for (String ppName : nonOrderedPostProcessorNames) {
          
          
     		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
     		nonOrderedPostProcessors.add(pp);
     		if (pp instanceof MergedBeanDefinitionPostProcessor) {
          
          
     			internalPostProcessors.add(pp);
     		}
     	}
     	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    
     	// Finally, re-register all internal BeanPostProcessors.
     	sortPostProcessors(internalPostProcessors, beanFactory);
     	registerBeanPostProcessors(beanFactory, internalPostProcessors);
    
     	// Re-register post-processor for detecting inner beans as ApplicationListeners,
     	// moving it to the end of the processor chain (for picking up proxies etc).
     	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
     }
    
  2. 此处着重分析beanFactory.getBean() Bean 工厂创建 BeanPostProcessor 对象的过程,追踪代码容易得知获取 Bean 调用到了 AbstractBeanFactory#doGetBean() 方法。这个方法很长,本文主要分析流程主干,也就是 createBean() 抽象方法

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
     		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
          
          
            
            ......
     		
     		// Check if bean definition exists in this factory.
     		BeanFactory parentBeanFactory = getParentBeanFactory();
     		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
          
          
     			// Not found -> check parent.
     			String nameToLookup = originalBeanName(name);
     			if (parentBeanFactory instanceof AbstractBeanFactory) {
          
          
     				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
     						nameToLookup, requiredType, args, typeCheckOnly);
     			}
     			else if (args != null) {
          
          
     				// Delegation to parent with explicit args.
     				return (T) parentBeanFactory.getBean(nameToLookup, args);
     			}
     			else if (requiredType != null) {
          
          
     				// No args -> delegate to standard getBean method.
     				return parentBeanFactory.getBean(nameToLookup, requiredType);
     			}
     			else {
          
          
     				return (T) parentBeanFactory.getBean(nameToLookup);
     			}
     		}
    
     		if (!typeCheckOnly) {
          
          
     			markBeanAsCreated(beanName);
     		}
    
     		try {
          
          
     			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
     			checkMergedBeanDefinition(mbd, beanName, args);
    
     			// Guarantee initialization of beans that the current bean depends on.
     			String[] dependsOn = mbd.getDependsOn();
     			if (dependsOn != null) {
          
          
     				for (String dep : dependsOn) {
          
          
     					if (isDependent(beanName, dep)) {
          
          
     						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
     								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
     					}
     					registerDependentBean(dep, beanName);
     					try {
          
          
     						getBean(dep);
     					}
     					catch (NoSuchBeanDefinitionException ex) {
          
          
     						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
     								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
     					}
     				}
     			}
    
     			// Create bean instance.
     			if (mbd.isSingleton()) {
          
          
     				sharedInstance = getSingleton(beanName, () -> {
          
          
     					try {
          
          
     						return createBean(beanName, mbd, args);
     					}
     					catch (BeansException ex) {
          
          
     						// Explicitly remove instance from singleton cache: It might have been put there
     						// eagerly by the creation process, to allow for circular reference resolution.
     						// Also remove any beans that received a temporary reference to the bean.
     						destroySingleton(beanName);
     						throw ex;
     					}
     				});
     				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
     			}
    
     			else if (mbd.isPrototype()) {
          
          
     				// It's a prototype -> create a new instance.
     				Object prototypeInstance = null;
     				try {
          
          
     					beforePrototypeCreation(beanName);
     					prototypeInstance = createBean(beanName, mbd, args);
     				}
     				finally {
          
          
     					afterPrototypeCreation(beanName);
     				}
     				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
     			}
    
     			else {
          
          
     				String scopeName = mbd.getScope();
     				final Scope scope = this.scopes.get(scopeName);
     				if (scope == null) {
          
          
     					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
     				}
     				try {
          
          
     					Object scopedInstance = scope.get(beanName, () -> {
          
          
     						beforePrototypeCreation(beanName);
     						try {
          
          
     							return createBean(beanName, mbd, args);
     						}
     						finally {
          
          
     							afterPrototypeCreation(beanName);
     						}
     					});
     					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
     				}
     				catch (IllegalStateException ex) {
          
          
     					throw new BeanCreationException(beanName,
     							"Scope '" + scopeName + "' is not active for the current thread; consider " +
     							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
     							ex);
     				}
     			}
     		}
     		catch (BeansException ex) {
          
          
     			cleanupAfterBeanCreationFailure(beanName);
     			throw ex;
     		}
     	}
    
     	......
     	
     	return (T) bean;
     }
    
  3. AbstractAutowireCapableBeanFactory#createBean() 方法中会调用 doCreateBean() 方法去创建 Bean 对象

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
     		throws BeanCreationException {
          
          
    
     	if (logger.isTraceEnabled()) {
          
          
     		logger.trace("Creating instance of bean '" + beanName + "'");
     	}
     	RootBeanDefinition mbdToUse = mbd;
    
     	// Make sure bean class is actually resolved at this point, and
     	// clone the bean definition in case of a dynamically resolved Class
     	// which cannot be stored in the shared merged bean definition.
     	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
     	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
          
          
     		mbdToUse = new RootBeanDefinition(mbd);
     		mbdToUse.setBeanClass(resolvedClass);
     	}
    
     	// Prepare method overrides.
     	try {
          
          
     		mbdToUse.prepareMethodOverrides();
     	}
     	catch (BeanDefinitionValidationException ex) {
          
          
     		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
     				beanName, "Validation of method overrides failed", ex);
     	}
    
     	try {
          
          
     		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
     		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
     		if (bean != null) {
          
          
     			return bean;
     		}
     	}
     	catch (Throwable ex) {
          
          
     		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
     				"BeanPostProcessor before instantiation of bean failed", ex);
     	}
    
     	try {
          
          
     		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
     		if (logger.isTraceEnabled()) {
          
          
     			logger.trace("Finished creating instance of bean '" + beanName + "'");
     		}
     		return beanInstance;
     	}
     	catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
          
          
     		// A previously detected exception with proper bean creation context already,
     		// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
     		throw ex;
     	}
     	catch (Throwable ex) {
          
          
     		throw new BeanCreationException(
     				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
     	}
     }
    
  4. AbstractAutowireCapableBeanFactory#doCreateBean() 方法中主要完成了以下工作,此处为了解决循环引用的问题,允许未创建完成的 Bean 对象提前暴露出来,主要是通过 Map 集合 earlySingletonObjects 缓存实现的

    1. createBeanInstance() 实例化 Bean 对象
    2. initializeBean() 初始化 Bean 对象
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    		throws BeanCreationException {
          
          
    
    	// Instantiate the bean.
    	BeanWrapper instanceWrapper = null;
    	if (mbd.isSingleton()) {
          
          
    		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    	}
    	if (instanceWrapper == null) {
          
          
    		instanceWrapper = createBeanInstance(beanName, mbd, args);
    	}
    	final Object bean = instanceWrapper.getWrappedInstance();
    	Class<?> beanType = instanceWrapper.getWrappedClass();
    	if (beanType != NullBean.class) {
          
          
    		mbd.resolvedTargetType = beanType;
    	}
    
    	......
    
    	// Eagerly cache singletons to be able to resolve circular references
    	// even when triggered by lifecycle interfaces like BeanFactoryAware.
    	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    			isSingletonCurrentlyInCreation(beanName));
    	if (earlySingletonExposure) {
          
          
    		if (logger.isTraceEnabled()) {
          
          
    			logger.trace("Eagerly caching bean '" + beanName +
    					"' to allow for resolving potential circular references");
    		}
    		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    	}
    
    	// Initialize the bean instance.
    	Object exposedObject = bean;
    	try {
          
          
    		populateBean(beanName, mbd, instanceWrapper);
    		exposedObject = initializeBean(beanName, exposedObject, mbd);
    	}
    	catch (Throwable ex) {
          
          
    		if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
          
          
    			throw (BeanCreationException) ex;
    		}
    		else {
          
          
    			throw new BeanCreationException(
    					mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    		}
    	}
    
    	if (earlySingletonExposure) {
          
          
    		Object earlySingletonReference = getSingleton(beanName, false);
    		if (earlySingletonReference != null) {
          
          
    			if (exposedObject == bean) {
          
          
    				exposedObject = earlySingletonReference;
    			}
    			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
          
          
    				String[] dependentBeans = getDependentBeans(beanName);
    				Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
    				for (String dependentBean : dependentBeans) {
          
          
    					if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
          
          
    						actualDependentBeans.add(dependentBean);
    					}
    				}
    				if (!actualDependentBeans.isEmpty()) {
          
          
    					throw new BeanCurrentlyInCreationException(beanName,
    							"Bean with name '" + beanName + "' has been injected into other beans [" +
    							StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
    							"] in its raw version as part of a circular reference, but has eventually been " +
    							"wrapped. This means that said other beans do not use the final version of the " +
    							"bean. This is often the result of over-eager type matching - consider using " +
    							"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
    				}
    			}
    		}
    	}
    
    	// Register bean as disposable.
    	try {
          
          
    		registerDisposableBeanIfNecessary(beanName, bean, mbd);
    	}
    	catch (BeanDefinitionValidationException ex) {
          
          
    		throw new BeanCreationException(
    				mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    	}
    
    	return exposedObject;
    }
    
  5. AbstractAutowireCapableBeanFactory#initializeBean() 方法会调用 invokeAwareMethods() 方法检查对象实现的接口,如果其实现了特定接口,则接口方法将被调用。此处异步任务的后置处理器 AsyncAnnotationBeanPostProcessor#setBeanFactory() 方法将被调用

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
          
          
    	if (System.getSecurityManager() != null) {
          
          
    		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
          
          
    			invokeAwareMethods(beanName, bean);
    			return null;
    		}, getAccessControlContext());
    	}
    	else {
          
          
    		invokeAwareMethods(beanName, bean);
    	}
    
    	Object wrappedBean = bean;
    	if (mbd == null || !mbd.isSynthetic()) {
          
          
    		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    	}
    
    	try {
          
          
    		invokeInitMethods(beanName, wrappedBean, mbd);
    	}
    	catch (Throwable ex) {
          
          
    		throw new BeanCreationException(
    				(mbd != null ? mbd.getResourceDescription() : null),
    				beanName, "Invocation of init method failed", ex);
    	}
    	if (mbd == null || !mbd.isSynthetic()) {
          
          
    		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    	}
    
    	return wrappedBean;
    }
    
    private void invokeAwareMethods(final String beanName, final Object bean) {
          
          
    	if (bean instanceof Aware) {
          
          
    		if (bean instanceof BeanNameAware) {
          
          
    			((BeanNameAware) bean).setBeanName(beanName);
    		}
    		if (bean instanceof BeanClassLoaderAware) {
          
          
    			ClassLoader bcl = getBeanClassLoader();
    			if (bcl != null) {
          
          
    				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
    			}
    		}
    		if (bean instanceof BeanFactoryAware) {
          
          
    			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    		}
    	}
    }
    
  6. AsyncAnnotationBeanPostProcessor#setBeanFactory() 方法可以看到其创建了异步任务切面 AsyncAnnotationAdvisor,该切面中包含了增强拦截器AnnotationAsyncExecutionInterceptor 和切入点AnnotationMatchingPointcut,将在后续创建 @Async 标注的 bean 时用于创建代理对象

    后续@Async 异步任务代理对象的生成及其生效原理不再继续分析,读者根据流程图理解即可

     public void setBeanFactory(BeanFactory beanFactory) {
          
          
     	super.setBeanFactory(beanFactory);
    
     	AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
     	if (this.asyncAnnotationType != null) {
          
          
     		advisor.setAsyncAnnotationType(this.asyncAnnotationType);
     	}
     	advisor.setBeanFactory(beanFactory);
     	this.advisor = advisor;
     }
    

猜你喜欢

转载自blog.csdn.net/weixin_45505313/article/details/107058248