通过在配置类上使用@Import注解,将User给注入进容器中,运行启动类,可以看到容器中有User对象:

image-20210226164625069

【2】导入ImportSelector的实现类

导入ImportSelector的实现类需要实现ImportSelector类,自定义逻辑返回需要导入的组件,返回的字符串数组即是要注入的组件,添加修改如下代码:

//?ImportSelector实现类

public?class?MyImportSelector?implements?ImportSelector?{

/**

*?@description?获取要导入到容器的组件全类名

*?@author?ONESTAR

*?@date?2021/2/25?15:49

*?@param?annotationMetadata:当前标注@Import注解类的所有注解信息

*?@throws

*?@return?java.lang.String[]

*/

public?String[]?selectImports(AnnotationMetadata?annotationMetadata)?{

return?new?String[]{“bean.Person”};

}

}

//?待注入的Person

public?class?Person?{

}

//?配置类

@Configuration

@Import({User.class,?MyImportSelector.class})???//使用@Import导入组件,ID默认是组件的全类名

public?class?AppConfig?{

}

ImportSelector实现类中获取要导入到容器的组件全类名,这里将ImportSelector实现类在配置类中使用@Import注解进行配置,运行启动类,可以看到容器中有Person对象:

image-20210227151242060

【3】导入ImportBeanDefinitionRegistrar的实现类

导入ImportBeanDefinitionRegistrar的实现类需要实现ImportBeanDefinitionRegistrar类,通过实现registerBeanDefinitions方法手动注册Bean到容器中,添加修改如下代码:

//?ImportBeanDefinitionRegistrar实现类

public?class?MyImportBeanDefinitionRegistrar?implements?ImportBeanDefinitionRegistrar?{

public?void?registerBeanDefinitions(AnnotationMetadata?annotationMetadata,?BeanDefinitionRegistry?beanDefinitionRegistry)?{

//?指定Bean的名称

RootBeanDefinition?beanDefinition?=?new?RootBeanDefinition(Animal.class);

beanDefinitionRegistry.registerBeanDefinition(“Animal”,?beanDefinition);

}

}

//?待注入的Animal

public?class?Animal?{

}

//?配置类

@Configuration

@Import({User.class,?MyImportSelector.class,?MyImportBeanDefinitionRegistrar.class})???//使用@Import导入组件,ID默认是组件的全类名

public?class?AppConfig?{

}

通过ImportBeanDefinitionRegistrar的实现类进行手动注册添加Bean,并在配置类中使用@Import注解进行配置,运行启动类,可以看到容器中有Animal对象:

image-20210227153057676

三、源码追踪

参考: https://blog.csdn.net/mamamalululu00000000/article/details/86711079

通过@Configuration注解,会进入到doProcessConfigurationClass方法,此时解析的是appConfigure,在doProcessConfigurationClass方法里面,有个执行@Import注解的方法,即processImports

this.processImports(configClass,?sourceClass,?this.getImports(sourceClass),?filter,?true);

@Import注解执行的时机,解析配置类的时候,由ConfigurationClassParser当中的processImports来处理,在分析processImports方法之前,咱们先来看看参数getImports方法:

【1】getImports方法

进入源码查看方法,这个方法就是获取所有的@import?里面的类,流程如下:

  1. 定义一个 visited 的集合,用作 是否已经 判断过的标志

  2. 这里就是获取sourceClass 上面的 所有的 annotation,并挨个判断, 如果不是 @import ,那就 进一步递归 调用 对应的 annotation,直到全部结束

  3. 加载sourceClass 里面 的@Import annotation 里面对应的类名 ,最后返回

//?获取所有的@import?里面的类

private?Set<ConfigurationClassParser.SourceClass>?getImports(ConfigurationClassParser.SourceClass?sourceClass)?throws?IOException?{

Set<ConfigurationClassParser.SourceClass>?imports?=?new?LinkedHashSet();

Set<ConfigurationClassParser.SourceClass>?visited?=?new?LinkedHashSet();

this.collectImports(sourceClass,?imports,?visited);

return?imports;

}

//?这里就是获取sourceClass?上面的?所有的?annotation,?如果不是?@import?,那就?进一步递归?调用?对应的?annotation,直到全部结束

private?void?collectImports(ConfigurationClassParser.SourceClass?sourceClass,?Set<ConfigurationClassParser.SourceClass>?imports,?Set<ConfigurationClassParser.SourceClass>?visited)?throws?IOException?{

if?(visited.add(sourceClass))?{

Iterator?var4?=?sourceClass.getAnnotations().iterator();

while(var4.hasNext())?{

ConfigurationClassParser.SourceClass?annotation?=?(ConfigurationClassParser.SourceClass)var4.next();

String?annName?=?annotation.getMetadata().getClassName();

if?(!annName.equals(Import.class.getName()))?{

this.collectImports(annotation,?imports,?visited);

}

}

imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(),?“value”));

}

}