通过在配置类上使用@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
?里面的类,流程如下:
-
定义一个 visited 的集合,用作 是否已经 判断过的标志
-
这里就是获取sourceClass 上面的 所有的 annotation,并挨个判断, 如果不是 @import ,那就 进一步递归 调用 对应的 annotation,直到全部结束
-
加载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"));
}
}
标签:Spring,class,注解,Import,annotation,public,sourceClass From: https://blog.51cto.com/u_15767217/11874830