Spring源码@Import详解
1、需要有一定基础才能看懂,忘谅解
定位到核心方法
2、找到具体调用的方法
// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
3、第一行就是
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
4、第一次进来的话,只有一个proccessor
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
返回值是ConfigrationClassPostProccessor类
5、然后调用
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
6、再调用for循环中
postProcessor.postProcessBeanDefinitionRegistry(registry);
7、进入返回值那个类中调用
processConfigBeanDefinitions(registry);
8、拿到基础类的beandefination 是个集合,调用
parser.parse(candidates);
9、调用第一个
try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); }
10、最终掉到
do { sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); }
11、终于到了关键地方
// Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
12、递归调用
getImports(sourceClass)
这个方法就是收集import进来的类
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); if (!annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } }
在内部又调用了外部方法,是个递归,需要注意
String annName = annotation.getMetadata().getClassName();获取到的不是当前的类名,而是souceClass对应的注解名称,最开始sourceClass是个普通的类,但是经过一次递归后,sourceClass就变成了
注解本身,也就是接口本身,所以第二次调用就是从注解本身获取它上面的注解名称,然后再看上面还有没有注解,直到最底层一级,然后调用最底层一级的
sourceClass.getAnnotationAttributes(Import.class.getName(), "value");因为递归一直走,会把所有最底层有import注解的类收集到imports中。完成@Import注解中类的收集。
进入中processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
很明显不同类型的Import会有不同的方法调用,不再细说
Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); }