springBean注册之@Import注解解析

前言

本文重点研究@Import注解的使用与源码解析

SpringIOC源码:@Configuration配置类解析过程一文中,Spring通过一系列操作后,会使用ConfigurationClassParser类的processImports方法解析@Import,本文源码讲解就从这里开始

一、@Import的使用

说明:只能标注在类上,属性是 Class<?>[] value()

1、注册普通bean

@Import(Person.class)
@Configuration 
public class App{}
public class Person {
}

其别名是“包名.类名”

2、注册配置类

@Import({TestConfig.class)
@Configuration
public class AppConfig {
}
@Configuration
public class TestConfig {
    @Bean
    public Person person(){
        return new Person();
    }
}

注意:这时候person的别名不是“包名.类名”,是和普通的一样,而TestConfig的别名是“包名.类名”

注意:如果主配置类AppConfig中如下

@Configuration
@Import({TestConfig.class)
public class AppConfig {
   @Bean
    public Person person(){
        return new Person();
    }
}

TestConfig中的person方法不会执行,而AppConfig中的会,除非AppConfig的没有

3、注册ImportSelector的实现类

ImportSelector是Spring中导入外部配置的核心接口

public class MyImport implements ImportSelector { 
   @Override 
   public String[] selectImports(AnnotationMetadata importingClassMetadata) { 
        return new String[]{Color.class.getName()}; } 
}
@Configuration  
@Import(MyImport.class) 
public class CarFactory { }

导入的Color的别名是cn.dao.Color 别名是“包名.类名”,

4、注册ImportBeanDefinitionRegistrar的实现类

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { 
     @Override 
     public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
       boolean sign = registry.containsBeanDefinition("car”);
       if(!sign){ 
           registry.registerBeanDefinition("color", new RootBeanDefinition(Color.class)); 
      } 
}
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class) 
public class CarFactory {
}

二、源码解析

1、一阶段解析

class ConfigurationClassParser {

private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		//根据{@code@Conditional}批注确定是否应跳过项。
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		
		//忽略代码.........
		
		// 递归地处理配置类及其超类层次结构。
		SourceClass sourceClass = asSourceClass(configClass);
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);
        //最终把解析到的类组装成ConfigurationClass形式放到缓存configurationClasses中
		this.configurationClasses.put(configClass, configClass);
	}

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
        
        //处理@Component注解
        
		//处理@PropertySource注解
		
		//处理@ComponentScan注解
		
		// 处理任何@Import注释
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// 处理任何@ImportResource注释
		
		// 处理单个@Bean方法
		
		// 处理接口上的默认方法
	
	}

        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 {
			    //循环@Import注解要value的值
				for (SourceClass candidate : importCandidates) {
				     //如果是ImportSelector类型
					if (candidate.isAssignable(ImportSelector.class)) {
						//获取class
						Class<?> candidateClass = candidate.loadClass();
						//实例当前ImportSelector对象
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						//如果当前selector实现了Aware接口,那么执行其具体的内部回调接口
						ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
						//如果value的值是DeferredImportSelector
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}//如果value的值不是DeferredImportSelector
						else {
						    //执行其selectImports方法。获取要注册的springbean全类名
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							//类型转换,可以忽略
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							//递归调用当前方法,处理要注册的类
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					 //如果value是ImportBeanDefinitionRegistrar类型
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
						ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
						//把当前ImportBeanDefinitionRegistrar对象缓存起来
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// 候选类不是ImportSelector或ImportBeanDefinitionRegistrar
						// 将其作为@Configuration类处理
						this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						//processConfigurationClass的底层是doProcessConfigurationClass方法
						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注解value值的对象。
2、判断他们的类型
3、如果是ImportSelector类型:再判断其是否是DeferredImportSelector类型;如果是把其收集起来,等到一阶段解析完成后在进行解析。如果不是,执行其selectImports方法,获取要注册的springBean信息。再次判断他们的类型直至他们是普通javaBean类型
4、如果是ImportBeanDefinitionRegistrar类型:把他放到缓存中,以便二阶段解析注册。
5、如果是普通javaBean类型:把他作为配置类,解析一阶段解析,直至其没有被@Configuration,@Bean,@Component,@ComponentScan,@Import,@ImportResource注解标注。这时候把他放到缓存configurationClasses中。以便二阶段解析注册。

普通javaBean类型:在这里的意思是候选类不是ImportSelector或ImportBeanDefinitionRegistrar

2、二阶段解析注册

#ConfigurationClassPostProcessor
//configClasses是一阶段缓存进去要注册的类,ImportSelector,ImportBeanDefinitionRegistrar
this.reader.loadBeanDefinitions(configClasses);

在这里我们只分析@Import注解部分

class ConfigurationClassBeanDefinitionReader {

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		 TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		 for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		 }
	  }
	  
    private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

		//忽略代码。。。。。。。
		
        //如果其是通过@Import注解注册过来的普通javabean,ImportBeanDefinitionRegistrar类型不会进来
		if (configClass.isImported()) {
		   //注册其BeanDefinition到容器Spring中
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		
		//....注册通过@bean注解标注的类
        
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		//解析ImportBeanDefinitionRegistrar类型,执行其registerBeanDefinitions方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

三、疑问

1、ImportSelector,ImportBeanDefinitionRegistrar以及DeferredImportSelector

在上面的processImports方法中已经讲解了对所有的@Import注解中value值为不同指的情况进行解析。有以下的情况:

1、ImportSelector接口的实现类
2、DeferredImportSelector接口的实现类
3、ImportBeanDefinitionRegistrar接口的实现类
4、非以上3中接口的实现类,也就是普通的类

这里主要讲解1到3这三个接口类的区别

ImportSelector

public interface ImportSelector {
	String[] selectImports(AnnotationMetadata importingClassMetadata);
}

ImportSelector接口作用将方法返回的字符串数组作为bean注入到容器中,注意这里的字符串需要是对象的全路径名称比如A.class.getName()这种。

ImportBeanDefinitionRegistrar

public interface ImportBeanDefinitionRegistrar {

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}

}

ImportBeanDefinitionRegistrar这个接口作用是,用户可以实现了之后来自定义来注册需要注册的bean。可以设置自定义的BeanNameGeneratorbean名称生成规则。

DeferredImportSelector

public interface DeferredImportSelector extends ImportSelector {

	default Class<? extends Group> getImportGroup() {
		return null;
	}

	interface Group {

	......

	}
  1. DeferredImportSelector是ImportSelector的一个扩展;
  2. ImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理之前,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理(注意,这里只是对@Bean修饰的方法的处理,并不是立即调用@Bean修饰的方法,这个区别很重要!);
  3. DeferredImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理;
  4. DeferredImportSelector的实现类可以用Order注解,或者实现Ordered接口来对selectImports的执行顺序排序;
发布了34 篇原创文章 · 获赞 0 · 访问量 1357

猜你喜欢

转载自blog.csdn.net/qq_41071876/article/details/105321547
今日推荐