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代码。
发表评论