提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、@Import 注解
- 二、@Import的原理解析
- 1.调用链
- 2. @Import 与Aware的问题
- 总结
前言
我们有许多的方式可以在spring 里加入BeanDefinition对象, 例如最常见的@Component,@Bean。
接下来我们介绍另外一种方式帮我们加入bean实例:@Import
提示:以下是本篇文章正文内容,下面案例可供参考
一、@Import 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
Class<?>[] value();
}
源码十分简单,而且也写明了可以配合 Configuration , ImportSelector, ImportBeanDefinitionRegistrar 来进行使用。
接下来我们来看看简单的例子。
@Component
@Import(ImportAwareTest.class)
public class TestImportBean {
}
@Import支持导入普通的没有@Configuration注解的类,并将其实例化加入IOC容器中, 这里由实现了ImportAware接口,所以必须得加上@Component注解,否者setImportMetadata不会执行(至于为什么,后面会讲到)
@Component
public class ImportAwareTest implements ImportAware {
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
System.out.println("----importMetadata---------"+ importMetadata);
}
}
@Import与ImportSelector配合,只需要将beanName 返回, 就可以讲该bean实例化加入IOC容器中。
public class ImportAwareTest implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{xxx.class};
}
}
@Import与ImportBeanDefinitionRegistrar 配合,由于第二个参数传递的是BeanDefinitionRegistry ,那么直接可以对IOC容器的Bean对象进行增删改查了。
public class ImportAwareTest implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder xxxService = BeanDefinitionBuilder.rootBeanDefinition(XXX.class);
registry.registerBeanDefinition("xxxx", xxxService.getBeanDefinition());
}
}
二、@Import的原理解析
1.调用链
SpringApplication.run(MyApplication.class, args) ->
SpringApplication run(Object source, String... args) ->
SpringApplication run(Object[] sources, String[] args) ->
SpringApplication run(String... args) ->
SpringApplication refreshContext(ConfigurableApplicationContext context) ->
SpringApplication refresh(ApplicationContext applicationContext) ->
EmbeddedWebApplicationContext refresh() ->
AbstractApplicationContext refresh() ->
AbstractApplicationContext invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) ->
PostProcessorRegistrationDelegate invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) ->
//重点就在于ConfigurationClassPostProcessor
ConfigurationClassPostProcessor postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) ->
ConfigurationClassPostProcessor processConfigBeanDefinitions(BeanDefinitionRegistry registry) ->
ConfigurationClassParser parse(Set<BeanDefinitionHolder> configCandidates) ->
//这里有三个parse的方法,我们只取其中一个来进行分析
ConfigurationClassParser parse(AnnotationMetadata metadata, String beanName) ->
ConfigurationClassParser processConfigurationClass(ConfigurationClass configClass) ->
ConfigurationClassParser doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
兜兜转转,终于到了本次讲解的重点代码。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//处理有@Component注解的类
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());
}
}
}
}
//本次的重点在这里,处理@Import注解
// 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;
}
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) {
//Import 的类 是否实现了ImportSelector接口
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
//实例化bean,并调用各类Aware方法。
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 {
//假如Bean实现了ImportSelector接口,则在这里调用了selectImports方法
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
//selectImports方法返回的是类的全限定名,递归调用processImports
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
//Import 的类 是否实现了ImportBeanDefinitionRegistrar接口
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
//实例化bean,并调用各类Aware方法。
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
//将该类加入importBeanDefinitionRegistrars 容器中
//registerBeanDefinitions的调用不在这里。将在后面执行
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());
//递归,直到没有@Import发现
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();
}
}
}
这里的主要流程: 1. 被Import 的类实现了ImportSelector接口,则执行selectImports方法。 2. 如果没有实现任何接口,则将该Import的类加入容器中。 3. 需要注意的是,类上可能有多层嵌套Import(如A类import B类,B类import C类),所以这里使用了递归。
ImportBeanDefinitionRegistrar的接口调用我们还没找到,接下来我们回到ConfigurationClassPostProcessorl类
ConfigurationClassPostProcessor processConfigBeanDefinitions(BeanDefinitionRegistry registry) ->
ConfigurationClassBeanDefinitionReader loadBeanDefinitions(Set<ConfigurationClass> configurationModel) ->
ConfigurationClassBeanDefinitionReader loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) ->
ConfigurationClassBeanDefinitionReader loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars)
ImportBeanDefinitionRegistrars这个Map是不是看起来似曾相似,对的,刚才的调用链中,spring将实现了ImportBeanDefinitionRegistrar的类,加入到了这个容器中。接下来的事情就显而易见了,直接foreach调用registerBeanDefinitions方法。
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry));
}
2. @Import 与Aware的问题
代码如下(示例):
之前说过了,被import的类如果实现了Aware接口,那么必须在类上加上@Component注解。这是为什么呢?
通过debug后发现,如果没有加上@Component注解,那么在beanDefinitionNames容器中没有找到该类。
后面有时间再查一下这个问题。
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容。