1. @import 介绍
1.1 @import 的作用
spring 中将一个普通类交给容器管理除了使用 @bean
及 @component
等注解再使用 @componentscan
扫描包之外,还可以使用 @import
注解
@import
只能用在类或者其他注解上 ,该注解能够方便快速地实现把实例加入到 spring 的 ioc 容器中,可用于导入第三方包
1.2 @import 的使用方式
@import
可以快速导入目标类,其主要有以下几种用法:
- 直接填写 class 数组,导入目标类
- 导入实现
importselector
接口的类 - 导入实现
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
注解核心原理。
简单来说,整个过程总共分为以下几步:
- 配置解析类
configurationclasspostprocessor
的注册 configurationclasspostprocessor
解析配置类,并将其注册到容器beanpostprocessor
后置处理器对象的优先创建@async
异步任务代理对象的生成及其生效原理
2.1 配置解析类configurationclasspostprocessor的注册
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; }
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(); }
springapplication#createbeandefinitionloader()
会创建 beandefinition 的加载器,最终创建的对象为 beandefinitionloader
protected beandefinitionloader createbeandefinitionloader( beandefinitionregistry registry, object[] sources) { return new beandefinitionloader(registry, sources); }
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)); }
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); }
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 解析配置类
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(); } ...... } }
abstractapplicationcontext#invokebeanfactorypostprocessors()
方法会调用 postprocessorregistrationdelegate.invokebeanfactorypostprocessors()
方法,这个方法的源码如下,可以看到其主要做了以下几件事:
- 从 bean 工厂中获取所有实现
beanfactorypostprocessor
接口的 bean 名称 - 通过 beanfactory.getbean() 去创建注册到容器中的
beanfactorypostprocessor
实例 - 通过
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(); }
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)); }
configurationclasspostprocessor#processconfigbeandefinitions()
方法,其内部比较重要的步骤如下:
- 生成 configurationclassparser 对象并调用其
parse()
方法用于解析配置类,缓存其配置的 bean - 使用 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(); } }
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); }
configurationclassparser#doprocessconfigurationclass()
是解析配置的核心方法,其主要的处理步骤如下,本文主要关注 processimports()
处理 @import
注解引入 bean 的流程
- processmemberclasses() 处理内部类
- processpropertysource() 处理加了@propertysource 注解的属性资源文件
- 解析出类上的@componentscan和@componentscans注解,然后根据其配置包路径扫描出所有需要交给spring管理的类,因为扫描出的类中可能也被加了@componentscan和@componentscans注解,因此需进行递归解析,直到所有标注了这两个注解的类被解析完毕
- processimports() 处理通过 @import注解配置的 bean
- 处理 @importresource 注解标注的配置文件
- doprocessconfigurationclass() 会被递归调用,则最终会处理配置类中加了@bean 注解的方法
- processinterfaces() 处理接口的默认方法。从jdk8开始,接口中的方法可以有自己的默认实现如果这个接口中的方法也加了@bean注解,也需要被解析
- 解析父类,如果被解析的配置类继承了某个类,那么配置类的父类也会被进行解析(父类是全类名以 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; }
configurationclassparser#processimports()
方法主要处理 3 种类型的 bean:
- importselector 接口的实现
- 实例化这个类的对象,然后调用其 selectimports() 方法去获得所需要的引入的配置类, 然后调用 processimports() 递归处理
- importbeandefinitionregistrar 接口的实现
- 实例化这个类的对象,将其添加到缓存到 map 集合中
- 普通类
- 把它当作 @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(); } } }
经过步骤5-7处理,引入的类都被解析完毕,接下来则会调用 configurationclassbeandefinitionreader#loadbeandefinitions()
将配置类中的解析出来的 bean 注册到容器中
从代码来看,其实核心是 loadbeandefinitionsforconfigurationclass() 方法完成注册工作,这里主要把需要注册的类分为了以下 4 类。
通过这个步骤,@enableasync 注解上经 @import 导入的 asyncconfigurationselector 选择器选中的配置类 proxyasyncconfiguration 注册到了容器中,并且这个配置类内部配置的asyncannotationbeanpostprocessor 也注册到了容器中
- 被 @configuration 标注的配置类或者 @import 导入的普通类
- 被 @bean 标注的方法配置的类
- 被 @importresource 导入的类
- 被 @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 后置处理器对象的优先创建
容器启动过程中abstractapplicationcontext#invokebeanfactorypostprocessors()
准备 bean 工厂的后置处理器完毕,就需要调用 abstractapplicationcontext#registerbeanpostprocessors()
将 bean 的后置处理器注册到容器中了。
这个过程通过 postprocessorregistrationdelegate.registerbeanpostprocessors()
方法完成,其流程与 bean 工厂后置处理器的注册大致相同:
- 首先 beanfactory.getbeannamesfortype() 获取所有实现 beanpostprocessor 接口的类名数组
- beanfactory.getbean() 创建 beanpostprocessor 实例
- 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)); }
此处着重分析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; }
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); } }
abstractautowirecapablebeanfactory#docreatebean()
方法中主要完成了以下工作,此处为了解决循环引用的问题,允许未创建完成的 bean 对象提前暴露出来,主要是通过 map 集合 earlysingletonobjects
缓存实现的
- createbeaninstance() 实例化 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()
方法会调用 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); } } }
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; }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持3w代码。
发表评论