当前位置: 代码网 > it编程>编程语言>Java > SpringBoot注解@Import原理之关于ConfigurationClassPostProcessor源码解析

SpringBoot注解@Import原理之关于ConfigurationClassPostProcessor源码解析

2024年07月18日 Java 我要评论
1. @import 介绍1.1 @import 的作用spring 中将一个普通类交给容器管理除了使用 @bean 及 @component等注解再使用 @componentscan 扫描包之外,还

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代码。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com