SpringBoot注解@Import原理之關(guān)于ConfigurationClassPostProcessor源碼解析
1. @Import 介紹
1.1 @Import 的作用
Spring 中將一個(gè)普通類交給容器管理除了使用 @Bean
及 @Component
等注解再使用 @ComponentScan
掃描包之外,還可以使用 @Import
注解
@Import
只能用在類或者其他注解上 ,該注解能夠方便快速地實(shí)現(xiàn)把實(shí)例加入到 Spring 的 IOC 容器中,可用于導(dǎo)入第三方包
1.2 @Import 的使用方式
@Import
可以快速導(dǎo)入目標(biāo)類,其主要有以下幾種用法:
- 直接填寫 class 數(shù)組,導(dǎo)入目標(biāo)類
- 導(dǎo)入實(shí)現(xiàn)
ImportSelector
接口的類 - 導(dǎo)入實(shí)現(xiàn)
ImportBeanDefinitionRegistrar
接口的類
1.2.1 直接導(dǎo)入目標(biāo)類
這種方式直接在@Import
中指定 class 數(shù)組,Spring 會(huì)在啟動(dòng)過程把 @Import 中配置的 bean 直接導(dǎo)入到 Spring 容器中,其 beanName 為類的全限定名,使用方法如下:
@Import({ abc.class , abd.class... }) public class Config { }
1.2.2 導(dǎo)入實(shí)現(xiàn) ImportSelector 接口的類
ImportSelector
是一個(gè)導(dǎo)入的選擇器,可以通過這個(gè)接口的實(shí)現(xiàn)決定引入哪些配置。
以 @EnableAsync
上通過@Import
導(dǎo)入的 AsyncConfigurationSelector
為例,Spring 容器會(huì)在啟動(dòng)過程中實(shí)例化該選擇器并調(diào)用其selectImports()
方法。
AsyncConfigurationSelector#selectImports()
根據(jù) @EnableAsync
中指定的模式選擇對(duì)應(yīng)的配置類,默認(rèn)代理模式,則導(dǎo)入指定的 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 導(dǎo)入實(shí)現(xiàn) ImportBeanDefinitionRegistrar 接口的類
ImportBeanDefinitionRegistrar
是一個(gè) bean 定義注冊(cè)器,以 @EnableAspectJAutoProxy
注解通過 @Import(AspectJAutoProxyRegistrar.class)
引入了注冊(cè)類 AspectJAutoProxyRegistrar
為例,在框架啟動(dòng)過程中會(huì)回調(diào)其實(shí)現(xiàn)的接口方法 AspectJAutoProxyRegistrar#registerBeanDefinitions()
方法將目標(biāo) bean 注冊(cè)到容器中
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 注冊(cè)目標(biāo)類的流程
以下流程圖以 @EnableAsync
注解使用 @Import
導(dǎo)入 AsyncConfigurationSelector
為例子,全流程展現(xiàn)了@Import
導(dǎo)入的類被解析為 BeanDefinition
并注冊(cè)到 Spring 容器中過程,以及 @Async
注解核心原理。
簡(jiǎn)單來說,整個(gè)過程總共分為以下幾步:
- 配置解析類
ConfigurationClassPostProcessor
的注冊(cè) ConfigurationClassPostProcessor
解析配置類,并將其注冊(cè)到容器BeanPostProcessor
后置處理器對(duì)象的優(yōu)先創(chuàng)建@Async
異步任務(wù)代理對(duì)象的生成及其生效原理
2.1 配置解析類ConfigurationClassPostProcessor的注冊(cè)
SpringApplication#run()
方法為框架啟動(dòng)的入口,啟動(dòng)過程中 prepareContext()
方法會(huì)為 Context 準(zhǔn)備必要的組件,其中就包括 ConfigurationClassPostProcessor
的注冊(cè)
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; }
SpringApplication#prepareContext()
中會(huì)調(diào)用 SpringApplication#load()
將必要的組件加載進(jìn)容器中,以下為 load()
方法實(shí)現(xiàn),可以看到方法內(nèi)部調(diào)用了 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(); }
SpringApplication#createBeanDefinitionLoader()
會(huì)創(chuàng)建 BeanDefinition 的加載器,最終創(chuàng)建的對(duì)象為 BeanDefinitionLoader
protected BeanDefinitionLoader createBeanDefinitionLoader( BeanDefinitionRegistry registry, Object[] sources) { return new BeanDefinitionLoader(registry, sources); }
BeanDefinitionLoader
的構(gòu)造方法中會(huì)初始化一系列的組件,其中包括了 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)); }
AnnotatedBeanDefinitionReader
的構(gòu)造方法會(huì)通過工具類AnnotationConfigUtils#registerAnnotationConfigProcessors()
注冊(cè)注解配置的處理器
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); }
AnnotationConfigUtils#registerAnnotationConfigProcessors()
方法會(huì)注冊(cè)許多 Spring 必須的處理器,本文主要關(guān)注 ConfigurationClassPostProcessor
這個(gè)配置類的后置處理器,可以看到此時(shí)已經(jīng)將其包裝到 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 解析配置類
Context 準(zhǔn)備完畢,會(huì)調(diào)用 SpringAppliction#refreshContext()
方法,最終調(diào)用到著名的 AbstractApplicationContext#refresh()
方法。
該方法體內(nèi)各個(gè)方法的作用可參考Spring啟動(dòng)流程源碼解析,本文主要關(guān)注 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(); } ...... } }
AbstractApplicationContext#invokeBeanFactoryPostProcessors()
方法會(huì)調(diào)用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
方法,這個(gè)方法的源碼如下,可以看到其主要做了以下幾件事:
- 從 bean 工廠中獲取所有實(shí)現(xiàn)
BeanFactoryPostProcessor
接口的 bean 名稱 - 通過 beanFactory.getBean() 去創(chuàng)建注冊(cè)到容器中的
BeanFactoryPostProcessor
實(shí)例 - 通過
invokeBeanFactoryPostProcessors()
方法調(diào)用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(); }
ConfigurationClassPostProcessor
已經(jīng)完成注冊(cè),且實(shí)現(xiàn)了 BeanFactoryPostProcessor
接口,則經(jīng)過步驟 2 ConfigurationClassPostProcessor#postProcessBeanFactory()
方法將被調(diào)用,可以看到方法內(nèi)部核心其實(shí)是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)); }
ConfigurationClassPostProcessor#processConfigBeanDefinitions()
方法,其內(nèi)部比較重要的步驟如下:
- 生成 ConfigurationClassParser 對(duì)象并調(diào)用其
parse()
方法用于解析配置類,緩存其配置的 Bean - 使用 ConfigurationClassBeanDefinitionReader 對(duì)象調(diào)用其
loadBeanDefinitions()
將配置類中的 Bean 注冊(cè)到容器中
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(); } }
ConfigurationClassParser#parse()
方法是解析配置類的核心入口,其最終調(diào)用到了 ConfigurationClassParser#processConfigurationClass()
方法。
這個(gè)方法主要處理邏輯是調(diào)用 doProcessConfigurationClass()
解析配置類,并將解析得到的 Bean 緩存在 Map 集合 configurationClasses
中供后續(xù)注冊(cè)使用
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); }
ConfigurationClassParser#doProcessConfigurationClass()
是解析配置的核心方法,其主要的處理步驟如下,本文主要關(guān)注 processImports()
處理 @Import
注解引入 Bean 的流程
- processMemberClasses() 處理內(nèi)部類
- processPropertySource() 處理加了@PropertySource 注解的屬性資源文件
- 解析出類上的@ComponentScan和@ComponentScans注解,然后根據(jù)其配置包路徑掃描出所有需要交給Spring管理的類,因?yàn)閽呙璩龅念愔锌赡芤脖患恿薂ComponentScan和@ComponentScans注解,因此需進(jìn)行遞歸解析,直到所有標(biāo)注了這兩個(gè)注解的類被解析完畢
- processImports() 處理通過 @Import注解配置的 Bean
- 處理 @ImportResource 注解標(biāo)注的配置文件
- doProcessConfigurationClass() 會(huì)被遞歸調(diào)用,則最終會(huì)處理配置類中加了@Bean 注解的方法
- processInterfaces() 處理接口的默認(rèn)方法。從JDK8開始,接口中的方法可以有自己的默認(rèn)實(shí)現(xiàn)如果這個(gè)接口中的方法也加了@Bean注解,也需要被解析
- 解析父類,如果被解析的配置類繼承了某個(gè)類,那么配置類的父類也會(huì)被進(jìn)行解析(父類是全類名以 java 開頭的JDK內(nèi)置的類例外)
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; }
ConfigurationClassParser#processImports()
方法主要處理 3 種類型的 Bean:
- ImportSelector 接口的實(shí)現(xiàn)
- 實(shí)例化這個(gè)類的對(duì)象,然后調(diào)用其 selectImports() 方法去獲得所需要的引入的配置類, 然后調(diào)用 processImports() 遞歸處理
- ImportBeanDefinitionRegistrar 接口的實(shí)現(xiàn)
- 實(shí)例化這個(gè)類的對(duì)象,將其添加到緩存到 Map 集合中
- 普通類
- 把它當(dāng)作 @Configuration 標(biāo)注的類調(diào)用最外層的
processConfigurationClass()
繼續(xù)處理
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(); } } }
經(jīng)過步驟5-7處理,引入的類都被解析完畢,接下來則會(huì)調(diào)用 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions()
將配置類中的解析出來的 Bean 注冊(cè)到容器中
從代碼來看,其實(shí)核心是 loadBeanDefinitionsForConfigurationClass() 方法完成注冊(cè)工作,這里主要把需要注冊(cè)的類分為了以下 4 類。
通過這個(gè)步驟,@EnableAsync 注解上經(jīng) @Import 導(dǎo)入的 AsyncConfigurationSelector 選擇器選中的配置類 ProxyAsyncConfiguration 注冊(cè)到了容器中,并且這個(gè)配置類內(nèi)部配置的AsyncAnnotationBeanPostProcessor 也注冊(cè)到了容器中
- 被 @Configuration 標(biāo)注的配置類或者 @Import 導(dǎo)入的普通類
- 被 @Bean 標(biāo)注的方法配置的類
- 被 @ImportResource 導(dǎo)入的類
- 被 @Import 導(dǎo)入的 ImportBeanDefinitionRegistrar 接口實(shí)現(xiàn)類
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 后置處理器對(duì)象的優(yōu)先創(chuàng)建
容器啟動(dòng)過程中AbstractApplicationContext#invokeBeanFactoryPostProcessors()
準(zhǔn)備 Bean 工廠的后置處理器完畢,就需要調(diào)用 AbstractApplicationContext#registerBeanPostProcessors()
將 Bean 的后置處理器注冊(cè)到容器中了。
這個(gè)過程通過 PostProcessorRegistrationDelegate.registerBeanPostProcessors()
方法完成,其流程與 Bean 工廠后置處理器的注冊(cè)大致相同:
- 首先 beanFactory.getBeanNamesForType() 獲取所有實(shí)現(xiàn) BeanPostProcessor 接口的類名數(shù)組
- beanFactory.getBean() 創(chuàng)建 BeanPostProcessor 實(shí)例
- registerBeanPostProcessors() 將 BeanPostProcessor 實(shí)例保存下來,在創(chuàng)建 Bean 的時(shí)候根據(jù)匹配規(guī)則確定某個(gè) BeanPostProcessor 是否需應(yīng)用于創(chuàng)建 Bean 代理對(duì)象
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)); }
此處著重分析beanFactory.getBean()
Bean 工廠創(chuàng)建 BeanPostProcessor 對(duì)象的過程,追蹤代碼容易得知獲取 Bean 調(diào)用到了 AbstractBeanFactory#doGetBean()
方法。
這個(gè)方法很長(zhǎng),本文主要分析流程主干,也就是 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; }
AbstractAutowireCapableBeanFactory#createBean()
方法中會(huì)調(diào)用 doCreateBean()
方法去創(chuàng)建 Bean 對(duì)象
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); } }
AbstractAutowireCapableBeanFactory#doCreateBean()
方法中主要完成了以下工作,此處為了解決循環(huán)引用的問題,允許未創(chuàng)建完成的 Bean 對(duì)象提前暴露出來,主要是通過 Map 集合 earlySingletonObjects
緩存實(shí)現(xiàn)的
- createBeanInstance() 實(shí)例化 Bean 對(duì)象
- initializeBean() 初始化 Bean 對(duì)象
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; }
AbstractAutowireCapableBeanFactory#initializeBean()
方法會(huì)調(diào)用 invokeAwareMethods()
方法檢查對(duì)象實(shí)現(xiàn)的接口,如果其實(shí)現(xiàn)了特定接口,則接口方法將被調(diào)用。
此處異步任務(wù)的后置處理器 AsyncAnnotationBeanPostProcessor#setBeanFactory()
方法將被調(diào)用
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); } } }
AsyncAnnotationBeanPostProcessor#setBeanFactory()
方法可以看到其創(chuàng)建了異步任務(wù)切面 AsyncAnnotationAdvisor
,該切面中包含了增強(qiáng)攔截器AnnotationAsyncExecutionInterceptor
和切入點(diǎn)AnnotationMatchingPointcut
,將在后續(xù)創(chuàng)建 @Async
標(biāo)注的 bean 時(shí)用于創(chuàng)建代理對(duì)象
后續(xù)@Async
異步任務(wù)代理對(duì)象的生成及其生效原理不再繼續(xù)分析,讀者根據(jù)流程圖理解即可
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; }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot Controller Post接口單元測(cè)試示例
今天小編就為大家分享一篇關(guān)于SpringBoot Controller Post接口單元測(cè)試示例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12Java CyclicBarrier源碼層分析與應(yīng)用
這篇文章主要介紹了Java CyclicBarrier的源碼層分析與應(yīng)用,CyclicBarrier也叫同步屏障,可以讓一組線程達(dá)到一個(gè)屏障時(shí)被阻塞,直到最后一個(gè)線程達(dá)到屏障,感興趣的的朋友可以參考下2023-12-12Java?任務(wù)調(diào)度框架?Quartz實(shí)操
這篇文章主要介紹了Java?任務(wù)調(diào)度框架?Quartz,Quartz是OpenSymphony開源組織在Job?scheduling領(lǐng)域又一個(gè)開源項(xiàng)目,完全由Java開發(fā),可以用來執(zhí)行定時(shí)任務(wù),類似于java.util.Timer。,下面我們來學(xué)習(xí)一下關(guān)于?Quartz更多的詳細(xì)內(nèi)容,需要的朋友可以參考一下2021-12-12使用Java程序模擬實(shí)現(xiàn)新冠病毒傳染效果
這篇文章主要介紹了用Java程序模擬實(shí)現(xiàn)新冠病毒傳染效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08Java基礎(chǔ)強(qiáng)化訓(xùn)練輸入錯(cuò)誤即結(jié)束進(jìn)程
本文主要介紹了Java編程的基礎(chǔ)知識(shí)強(qiáng)化應(yīng)用,文中實(shí)例涉及到了許多基礎(chǔ)知識(shí),new對(duì)象,控制臺(tái)輸入,if語句等。很實(shí)用,需要的朋友可以參考下2017-09-09Java判斷中英文符號(hào)、標(biāo)點(diǎn)的實(shí)現(xiàn)
本篇文章主要介紹了Java判斷中英文符號(hào)、標(biāo)點(diǎn)的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10springBoot熱部署、請(qǐng)求轉(zhuǎn)發(fā)與重定向步驟詳解
這篇文章主要介紹了springBoot熱部署、請(qǐng)求轉(zhuǎn)發(fā)與重定向,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06