ConfigurationClassParser.java
parse(){
processConfigurationClass()
// 处理selectImport 类,这里面自动装配的东西
this.deferredImportSelectorHandler.process();
}
ConfigurationClassParser.java
//开始循环解析包含指定注解的集合对象中的数据public void parse(Set configCandidates) {// 循环遍历configCandidatesfor (BeanDefinitionHolder holder : configCandidates) {// 获取BeanDefinitionBeanDefinition bd = holder.getBeanDefinition();// 根据BeanDefinition类型的不同,调用parse不同的重载方法,实际上最终都是调用processConfigurationClass()方法try {// 注解类型if (bd instanceof AnnotatedBeanDefinition) { // 注意,调用同名方法parse()->processConfigurationClass()->doProcessConfigurationClass(位置一)parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}// 有class对象的 。抽象类else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else {parse(bd.getBeanClassName(), holder.getBeanName());}}//上面的parse,只是解析Componet等属性,// 对于@Import的解析,普通的对象,直接进bd放到configurationClasses中,this.reader.loadBeanDefinitions(configClasses);// 对于实现ImportSelector接口的,放到deferredImportSelectorHandler列表中,此处开始回到处理了。// 获取所有的配置,遍历,调用处理import注解的方法,如果是普通的类,直接放进configurationClasses(键是对应上面configClasses)中//此处开始处理handler中的class ,加载springboot中的自动装配的配置this.deferredImportSelectorHandler.process();
}
接上面位置一处。
processConfigurationClass(){
//开始解析各种注解。里面有@Component注解等,启动注意@Import注解//位置二sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);// 把解析到的结果保存起来。注意:如果Import是普通类,那么这里能保存上
this.configurationClasses.put(configClass, configClass);
}
承接上面的位置二
doProcessConfigurationClass{
// 处理 @Import注解。查找所有的@import注解,找到注解中的类并实例化。直接处理或者加入handler中
processImports(configClass, sourceClass, getImports(sourceClass), filter, true)
;
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection importCandidates, Predicate exclusionFilter,boolean checkForCircularImports) {// 如果使用@Import注解修饰的类集合为空,那么直接返回if (importCandidates.isEmpty()) {return;}....try {// 遍历每一个@Import注解的类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();// 通过反射生成一个ImportSelect对象ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,this.environment, this.resourceLoader, this.registry);// 获取选择器的额外过滤器Predicate selectorFilter = selector.getExclusionFilter();if (selectorFilter != null) {exclusionFilter = exclusionFilter.or(selectorFilter);}// 判断引用选择器是否是DeferredImportSelector接口的实例// 如果是则应用选择器将会在所有的配置类都加载完毕后加载if (selector instanceof DeferredImportSelector) {// 重点核心-用来实现自动装配。。。。。将选择器添加到deferredImportSelectorHandler实例中,预留到所有的配置类加载完成后统一处理自动化配置类this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);}else {// 获取引入的类,然后使用递归方式将这些类中同样添加了@Import注解引用的类String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);// 重点。递归处理。被Import进来的类也有可能@Import注解processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);}}// 如果是实现了ImportBeanDefinitionRegistrar接口的bdelse if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar ->// delegate to it to register additional bean definitions// 候选类是ImportBeanDefinitionRegistrar -> 委托给当前注册器注册其他beanClass> candidateClass = candidate.loadClass();ImportBeanDefinitionRegistrar registrar =ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,this.environment, this.resourceLoader, this.registry);/** * 放到当前configClass的importBeanDefinitionRegistrars中;在ConfigurationClassPostProcessor处理configClass时会随之一起处理 */configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());}else { this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//说明仅仅是一个普通的类,还是解析它,其实里面什么都没处理,但是把它加入到configurationClasses中了,然后加载bd就有了processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);}}}....}}
其中SpringBoot
中的自动装配类AutoConfigurationImportSelector implements DeferredImportSelector
,就是实现了DeferredImportSelector
接口。
经过上面的步骤,说有的@Import
标记的处理完成。
=》 // 回调,处理@Import 放进去的选择器 ,SpringBoot的自动装配
this.deferredImportSelectorHandler.process();
->handler.processGroupImports();
--> // 理解的重点// getImports 获取到所有要装备的类,然后再遍历处理**grouping.getImports().forEach{//循环遍历,再调用自动装备的类,可能自动装配的类还有@Import注解// 更为重要的是,解析该类的时候,如果是普通类,那么调用processConfigurationClass处理一遍,最后把// bean信息放到this.configurationClasses.put(configClass, configClass);中去了。那么接下来就能放到容器的bdMaps中,等待实例化processImports(...)
}
--->public Iterable getImports() {for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {//调用process 方法了,这里过度到SpringBoot this.group.process(deferredImport.getConfigurationClass().getMetadata(),deferredImport.getImportSelector());}return this.group.selectImports();}
==============================到SpringBoot===============================
AutoConfigurationImportSelector#process(){->getAutoConfigurationEntry(..)
}protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {//获取所有的自动装配的配置。本例获取到130个List configurations = getCandidateConfigurations(annotationMetadata, attributes);configurations = removeDuplicates(configurations);Set exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);//排除掉不符合条件的configurations.removeAll(exclusions);configurations = getConfigurationClassFilter().filter(configurations);fireAutoConfigurationImportEvents(configurations, exclusions);//本例还有34个return new AutoConfigurationEntry(configurations, exclusions);}
加上@Component
注解,
public class TestSelfTag {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");User user=(User)context.getBean("user");}
}
@Component
@Import(User.class)
public class MyImportTestBean {
}
xml形式启动的时候,加上这个注解,才能doScan 扫描进去,放bdMaps中。
在ConfigurationClassPostProcessor 解析的时候,获取所有的已经注册的bd
String[] candidateNames = registry.getBeanDefinitionNames();
,如果不加这个注解,那么没放进去,
获取不到,就没法解析了,@Import就不生效了。
public static void main(String[] args) throws NoSuchMethodException {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();//注册bd到容器ac.register(MyTestConfiguration.class);ac.refresh();}
@Component
@ComponentScan(basePackages="com.songbl.selftag")
public class MyTestConfiguration { }
对于注解启动的,调用register方法注册了bean信息,后面获取的时候,
//获得上面注册MyTestConfiguration的bdString[] candidateNames = registry.getBeanDefinitionNames();if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {// 添加到对应的集合对象中(带注解的放进去);本例MyTestConfiguration 被@ComponentScan(basePackages="com.songbl.selftag")configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}
// 然后parse(上面准备的列表configCandidates),递归处理,本例到这里开始处理@ComponentScan(basePackages="com.songbl.selftag")了
总结:想让生效,就要用@Component 或者衍生注解 标记,使得扫描进去,才有机会被处理
下一篇: 《陶罐和铁罐》教学反思