spring源码:@Import注解

本文详细探讨了Spring框架中@Import注解的作用,包括如何引入bean、ImportSelector和ImportBeanDefinitionRegistrar接口的使用。通过源码分析,解释了@Import注解在配置类中的处理流程,涉及ImportSelector的递归解析以及ImportBeanDefinitionRegistrar的注册过程,最终将bean转换为BeanDefinition并存入BeanDefinitionMap。
摘要由CSDN通过智能技术生成

目的

前面的文章@Bean源码解析有说到,将一个bean,转换成BeanDefinition,并存入BeanDefinitionMap有三种方式;本文,我们要说的是@Import注解这种方式;
@Import是用来引入bean的;和本文相关的,我们需要关注ImportSelector和ImportBeanDefinitionRegistrar

接口说明

ImportBeanDefinitionRegistrar该接口,定义了一个public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

该方法的实现类,可以完成将bean添加到beanDefinitionMap中;因为在该方法中,可以获取到BeanDefinitionRegistry,只是:如果我们程序员自己去提供一个该接口的实现类,需要我们自己在接口实现类中,声明一个beanDefinition对象;并给beanDefinition对象设置属性
也可以在该方法中,修改已经存在于BeanDefinitionMap中的beanDefinition对象;

ImportSelector
该接口定义的方法,返回的是一个数组集合,我们只需要在实现类中定义我们要注入的bean的全类名,并放到return的集合中,即可;springboot的自动注入就是利用这个原理的,
通过SpringFactoriesLoader.loadFactoryNames获取到所有jar包中定义的要自动注入的bean对应的全类名;然后,spring会对所有要注入的bean进行解析;

源码

我前面的博客,有说到过,所有将bean转换为BeanDefinition的操作,都是在

org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

这个方法中完成的,我们本次要说的@Import注解的处理,也是在这个方法内部完成的;

这个gif是postProcessBeanDefinitionRegistry方法内部的调用逻辑
我们直接来看processImports(configClass, sourceClass, getImports(sourceClass), true);这行代码完成的动作;因为这个方法是本篇文章所要关注的

解析Import注解

getImports(sourceClass):这个方法内部嵌套的比较简单,就是获取到当前配置类上所有的注解,然后获取到@Import注解对应的value,也即:import注入的类

我们接着来看org.springframework.context.annotation.ConfigurationClassParser#processImports这个方法的处理:
先说这个方法的整体处理逻辑:

Import注解引入的类,有三种情况

  1. ImportSelector:
    1.1 判断Import引入的ImportSelector的实现类是否是DeferredImportSelector的实现类;DeferredImportSelector这个接口,在springboot自动注入的时候有用到;可以看下图1 AutoConfigurationImportSelector的继承关系:

    1.2 如果是非DeferredImportSelector的实现类,就正常处理:ImportSelector的实现类中,return的全类名数组; 在这里, 会依次解析每个类,防止要注入的类中有ImportSelector和ImportBeanDefinitionRegistrar的实现类;
    对于ImportSelector实现类,返回的普通bean存放到了configurationClasses中 会在org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(java.util.Set)方法中初始化,完成bean到BeanDefinition的转换

  2. ImportBeanDefinitionRegistrar:
    这里的处理比较简单;将实现类的registrar对象和metadata存入到importBeanDefinitionRegistrars这个map中,也是在org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(java.util.Set)进行beanDefinition对象的生成

  3. 普通类(bean):
    存入到了configurationClasses这个集合中;如果ImportSelector实现类返回的bean就是一个普通bean,那就会在第一次递归调用processImports的时候,在第三步这里添加到集合中;否则,会一直递归调用,直到解析到import的是普通bean;

也即:对于ImportBeanDefinitionRegistrar的实现类,直接存入到了map集合中;对于ImportSelector的实现类,需要在解析return的所有bean,防止return的bean中还有ImportSelector或者ImportBeanDefinitionRegistrar的实现类

图1

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));
	
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值