栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Spring】@Import、ImportSelector、ImportBeanDefinitionRegistrar的使用与源码分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Spring】@Import、ImportSelector、ImportBeanDefinitionRegistrar的使用与源码分析

@import是一个注解,专门用来导入实现了importSelector和importBeanDefinitionRegistrar接口的类,当然也可以用来导入普通的Bean。

@import的使用 @import+普通Bean
package com.morris.spring.demo.annotation;

import com.morris.spring.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.import;


@import(User.class)
public class importSimpleBeanDemo {

	@Test
	public void testimportSingleBean() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(importSimpleBeanDemo.class);
		User user = applicationContext.getBean(User.class);
		System.out.println(user);
	}

}

运行结果如下:

User(username=null, age=0)

可见User类上未加@Component注解,可以通过@import注解将User对象注入到Spring容器中。

@import+importSelector

importSelectorBean实现了importSelector接口的selectimports()方法,该方法的返回值就是返回需要实例化的Bean的全限定名。

package com.morris.spring.entity.imports;

import org.springframework.context.annotation.importSelector;
import org.springframework.core.type.Annotationmetadata;

public class importSelectorBean implements importSelector {
	@Override
	public String[] selectimports(Annotationmetadata importingClassmetadata) {
		return new String[]{"com.morris.spring.entity.User"};
	}
}

importSelectorBeanDemo中使用了@import注解注入importSelector。

package com.morris.spring.entity.imports;

import org.springframework.context.annotation.importSelector;
import org.springframework.core.type.Annotationmetadata;

public class importSelectorBean implements importSelector {
	
	@Override
	public String[] selectimports(Annotationmetadata importingClassmetadata) {
		return new String[]{"com.morris.spring.entity.User"};
	}
}

运行结果如下:

User(username=null, age=0)
false

可见User类上未加@Component注解,可以通过@import+importSelector将User对象注入到Spring容器中,但是importSelector对象本身并未被Spring管理。

@import+importBeanDefinitionRegistrar

importBeanDefinitionRegistrarBean实现了importBeanDefinitionRegistrar接口的registerBeanDefinitions()方法,该方法可以通过BeanDefinitionRegistry参数向容器中注入BeanDefinition,从而实现将Bean加入到Spring容器中。

package com.morris.spring.entity.imports;

import com.morris.spring.entity.User;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.importBeanDefinitionRegistrar;
import org.springframework.core.type.Annotationmetadata;

public class importBeanDefinitionRegistrarBean implements importBeanDefinitionRegistrar {


	
	@Override
	public void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {

		System.out.println(importingClassmetadata.getAnnotationTypes());

		GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
		genericBeanDefinition.setBeanClass(User.class);
		registry.registerBeanDefinition("user", genericBeanDefinition);
	}

}

importBeanDefinitionRegistrarBeanDemo中使用了@import注解注入importBeanDefinitionRegistrarBean。

package com.morris.spring.demo.annotation;

import com.morris.spring.entity.User;
import com.morris.spring.entity.imports.importBeanDefinitionRegistrarBean;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.import;


@import(importBeanDefinitionRegistrarBean.class)
public class importBeanDefinitionRegistrarBeanDemo {

	@Test
	public void testimportSingleBean() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(importBeanDefinitionRegistrarBeanDemo.class);
		User user = applicationContext.getBean(User.class);
		System.out.println(user);
		System.out.println(applicationContext.containsBean("importBeanDefinitionRegistrarBean"));
	}

}

运行结果如下:

User(username=null, age=0)
false

可见User类上未加@Component注解,可以通过@import+importBeanDefinitionRegistrar将User对象注入到Spring容器中,但是importBeanDefinitionRegistrar对象本身并未被Spring管理。

源码分析

带着下面的问题进行分析:

importSelector和importBeanDefinitionRegistrar都是通过@import注解导入,那么@import注解所在的类是何时被扫描的?importSelector和importBeanDefinitionRegistrar接口的方法是何时被调用的?importSelector和importBeanDefinitionRegistrar对象为什么没有被加入到Spring容器中? @import的扫描

首先会从容器中取出所有的配置类(@Configuration、@Component、@ComponentScan、@import、@importResource、@Bean),因为这些类上面可能会有@import注解。

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();

	// 先收集有@Configuration、@Component、@ComponentScan、@import、@importResource、@Bean的BD
	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			// 进来需要@Component、@ComponentScan、@import、@importResource、@Bean
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}
... ...

获取类上面的@import注解:
org.springframework.context.annotation.ConfigurationClassParser#getimports

private Set getimports(SourceClass sourceClass) throws IOException {
	Set imports = new linkedHashSet<>();
	Set visited = new linkedHashSet<>();
	collectimports(sourceClass, imports, visited);
	return imports;
}

private void collectimports(SourceClass sourceClass, Set imports, Set visited)
		throws IOException {
	if (visited.add(sourceClass)) {
		for (SourceClass annotation : sourceClass.getAnnotations()) {
			String annName = annotation.getmetadata().getClassName();
			if (!annName.equals(import.class.getName())) {
				collectimports(annotation, imports, visited);
			}
		}
		imports.addAll(sourceClass.getAnnotationAttributes(import.class.getName(), "value"));
	}
}

然后类上面有@import注解的才会调用processimports()方法。
org.springframework.context.annotation.ConfigurationClassParser#processimports

private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection importCandidates, Predicate exclusionFilter,
		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)) {
					// 处理importSelector
					// Candidate class is an importSelector -> delegate to it to determine imports
					Class candidateClass = candidate.loadClass(); // 加载importSelector
					importSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, importSelector.class,
							this.environment, this.resourceLoader, this.registry); // 反射实例化importSelector
					Predicate selectorFilter = selector.getExclusionFilter();
					if (selectorFilter != null) {
						exclusionFilter = exclusionFilter.or(selectorFilter);
					}
					if (selector instanceof DeferredimportSelector) {
						// 特殊处理DeferredimportSelector
						this.deferredimportSelectorHandler.handle(configClass, (DeferredimportSelector) selector);
					}
					else {
						// 调用selectimports方法
						String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata());
						Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
						// 又递归,实际上会进入下面的else
						processimports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
					}
				}
				else if (candidate.isAssignable(importBeanDefinitionRegistrar.class)) {
					// Candidate class is an importBeanDefinitionRegistrar ->
					// delegate to it to register additional bean definitions
					// 处理importBeanDefinitionRegistrar
					Class candidateClass = candidate.loadClass();
					// 实例化importBeanDefinitionRegistrar
					importBeanDefinitionRegistrar registrar =
							ParserStrategyUtils.instantiateClass(candidateClass, importBeanDefinitionRegistrar.class,
									this.environment, this.resourceLoader, this.registry);
					// 这里只加入到configClass的importBeanDefinitionRegistrars容器中,并没有调用registerBeanDefinitions方法
					// registerBeanDefinitions方法是在哪里调用的呢?
					configClass.addimportBeanDefinitionRegistrar(registrar, currentSourceClass.getmetadata());
				}
				else {
					// Candidate class not an importSelector or importBeanDefinitionRegistrar ->
					// process it as an @Configuration class
					// 通过importSelector导入的类会进入这里,通过@import注入的普通类会进入这里
					// 通过importSelector导入的类会从这里加入到importStack
					this.importStack.registerimport(
							currentSourceClass.getmetadata(), candidate.getmetadata().getClassName());
					// 当成一个配置类来循环处理
					processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
				}
			}
		}
		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();
		}
	}
}

从上面的源码可以看出:

    importSelector会被直接反射实例化,然后调用selectimports()方法,将返回值放入到importStack中,注意importSelector本身没有被Spring容器所管理。然后又调用递归processimports方法,这样会进入本方法的else,当selectimports()导入的类当成一个配置类来处理。importBeanDefinitionRegistrar也会被直接反射实例化,然后加入到ConfigClass.importBeanDefinitionRegistrars属性中,importBeanDefinitionRegistrar.registerBeanDefinitions()此时并没有被调用。通过importSelector导入的类和通过@import注入的普通类会进入else代码块,当成一个配置类来循环处理,processConfigurationClass方法的最后一行会将所有的配置类加入到容器configurationClasses中。

那么configurationClasses中的配置类何时加入到Spring容器中呢?

importBeanDefinitionRegistrar.registerBeanDefinitions方法是在哪里调用的呢?

loadBeanDefinitions

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions

public void loadBeanDefinitions(Set configurationModel) {
	TrackedConditionevaluator trackedConditionevaluator = new TrackedConditionevaluator();
	for (ConfigurationClass configClass : configurationModel) {
		// 从配置类中加载BeanDefinition
		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()) {
		// 通过importSelector导入的类和通过@import注入的普通类在这里注入BeanDefinition
		registerBeanDefinitionForimportedConfigurationClass(configClass);
	}
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		// 注入@Bean注解的BeanDefinition
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}
	loadBeanDefinitionsFromimportedResources(configClass.getimportedResources());
	// importBeanDefinitionRegistrar.registerBeanDefinitions的调用
	loadBeanDefinitionsFromRegistrars(configClass.getimportBeanDefinitionRegistrars());
}

通过importSelector导入的类和通过@import注入的普通类在这里注入BeanDefinition

private void registerBeanDefinitionForimportedConfigurationClass(ConfigurationClass configClass) {
	Annotationmetadata metadata = configClass.getmetadata();
	AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
	Scopemetadata scopemetadata = scopemetadataResolver.resolveScopemetadata(configBeanDef);
	configBeanDef.setScope(scopemetadata.getScopeName());
	String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
	AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopemetadata, definitionHolder, this.registry);
	this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
	configClass.setBeanName(configBeanName);
	if (logger.isTraceEnabled()) {
		logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
	}
}

importBeanDefinitionRegistrar.registerBeanDefinitions()方法的调用:

private void loadBeanDefinitionsFromRegistrars(Map registrars) {
	// 调用importBeanDefinitionRegistrar.registerBeanDefinitions()
	registrars.forEach((registrar, metadata) ->
			registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/774669.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号