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 中指定的模式選擇對應(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 定義注冊器,以 @EnableAspectJAutoProxy注解通過 @Import(AspectJAutoProxyRegistrar.class) 引入了注冊類 AspectJAutoProxyRegistrar 為例,在框架啟動(dòng)過程中會(huì)回調(diào)其實(shí)現(xiàn)的接口方法 AspectJAutoProxyRegistrar#registerBeanDefinitions()方法將目標(biāo) 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 注冊目標(biāo)類的流程
以下流程圖以 @EnableAsync 注解使用 @Import 導(dǎo)入 AsyncConfigurationSelector 為例子,全流程展現(xiàn)了@Import 導(dǎo)入的類被解析為 BeanDefinition 并注冊到 Spring 容器中過程,以及 @Async注解核心原理。
簡單來說,整個(gè)過程總共分為以下幾步:
- 配置解析類
ConfigurationClassPostProcessor的注冊 ConfigurationClassPostProcessor解析配置類,并將其注冊到容器BeanPostProcessor后置處理器對象的優(yōu)先創(chuàng)建@Async異步任務(wù)代理對象的生成及其生效原理
2.1 配置解析類ConfigurationClassPostProcessor的注冊
SpringApplication#run() 方法為框架啟動(dòng)的入口,啟動(dòng)過程中 prepareContext() 方法會(huì)為 Context 準(zhǔn)備必要的組件,其中就包括 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;
}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)建的對象為 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()注冊注解配置的處理器
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ì)注冊許多 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)建注冊到容器中的
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)完成注冊,且實(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 對象并調(diào)用其
parse()方法用于解析配置類,緩存其配置的 Bean - 使用 ConfigurationClassBeanDefinitionReader 對象調(diào)用其
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();
}
}ConfigurationClassParser#parse() 方法是解析配置類的核心入口,其最終調(diào)用到了 ConfigurationClassParser#processConfigurationClass()方法。
這個(gè)方法主要處理邏輯是調(diào)用 doProcessConfigurationClass()解析配置類,并將解析得到的 Bean 緩存在 Map 集合 configurationClasses 中供后續(xù)注冊使用
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è)類的對象,然后調(diào)用其 selectImports() 方法去獲得所需要的引入的配置類, 然后調(diào)用 processImports() 遞歸處理
- ImportBeanDefinitionRegistrar 接口的實(shí)現(xiàn)
- 實(shí)例化這個(gè)類的對象,將其添加到緩存到 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 注冊到容器中
從代碼來看,其實(shí)核心是 loadBeanDefinitionsForConfigurationClass() 方法完成注冊工作,這里主要把需要注冊的類分為了以下 4 類。
通過這個(gè)步驟,@EnableAsync 注解上經(jīng) @Import 導(dǎo)入的 AsyncConfigurationSelector 選擇器選中的配置類 ProxyAsyncConfiguration 注冊到了容器中,并且這個(gè)配置類內(nèi)部配置的AsyncAnnotationBeanPostProcessor 也注冊到了容器中
- 被 @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 后置處理器對象的優(yōu)先創(chuàng)建
容器啟動(dòng)過程中AbstractApplicationContext#invokeBeanFactoryPostProcessors() 準(zhǔn)備 Bean 工廠的后置處理器完畢,就需要調(diào)用 AbstractApplicationContext#registerBeanPostProcessors() 將 Bean 的后置處理器注冊到容器中了。
這個(gè)過程通過 PostProcessorRegistrationDelegate.registerBeanPostProcessors() 方法完成,其流程與 Bean 工廠后置處理器的注冊大致相同:
- 首先 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 代理對象
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 對象的過程,追蹤代碼容易得知獲取 Bean 調(diào)用到了 AbstractBeanFactory#doGetBean() 方法。
這個(gè)方法很長,本文主要分析流程主干,也就是 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 對象
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 對象提前暴露出來,主要是通過 Map 集合 earlySingletonObjects 緩存實(shí)現(xiàn)的
- createBeanInstance() 實(shí)例化 Bean 對象
- 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;
}AbstractAutowireCapableBeanFactory#initializeBean() 方法會(huì)調(diào)用 invokeAwareMethods() 方法檢查對象實(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)建代理對象
后續(xù)@Async 異步任務(wù)代理對象的生成及其生效原理不再繼續(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)文章
CompletableFuture創(chuàng)建及功能使用全面詳解
這篇文章主要為大家介紹了CompletableFuture創(chuàng)建及功能使用全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Java之不通過構(gòu)造函數(shù)創(chuàng)建一個(gè)對象問題
這篇文章主要介紹了Java之不通過構(gòu)造函數(shù)創(chuàng)建一個(gè)對象問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
SpringBoot修改內(nèi)置tomcat版本的操作步驟
生產(chǎn)環(huán)境使用的外部部署Tomcat還是內(nèi)置Tomcat由于版本安全漏洞,往往需要升級(jí)到指定的安全版本,本文演示一下SpringBoot升級(jí)內(nèi)置的Tomcat版本,感興趣的小伙伴跟著小編一起來看看吧2024-07-07
spring?boot3自動(dòng)配置與手動(dòng)配置的全過程
本文給大家介紹了spring?boot3自動(dòng)配置與手動(dòng)配置的全過程,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2026-01-01
Java使用easyExcel導(dǎo)出數(shù)據(jù)及單元格多張圖片
除了平時(shí)簡單的數(shù)據(jù)導(dǎo)出需求外,我們也經(jīng)常會(huì)遇到一些有固定格式或者模板要求的數(shù)據(jù)導(dǎo)出,下面這篇文章主要給大家介紹了關(guān)于Java使用easyExcel導(dǎo)出數(shù)據(jù)及單元格多張圖片的相關(guān)資料,需要的朋友可以參考下2023-05-05
SpringBoot 快速實(shí)現(xiàn) api 加密的方法
在項(xiàng)目中,為了保證數(shù)據(jù)的安全,我們常常會(huì)對傳遞的數(shù)據(jù)進(jìn)行加密,常用的加密算法包括對稱加密(AES)和非對稱加密(RSA),本文給大家介紹SpringBoot 快速實(shí)現(xiàn) api 加密,感興趣的朋友一起看看吧2023-10-10

