imports是一个在spring体系里很是重要的注解,基本每一个Enable开头的注解必然有一个import注解。接下来咱们深刻研究下import的做用。看小节的同窗建议先取看PostProcessorRegistrationDelegate与BeanFactoryPostProcessor体系和AnnotationConfigUtilsjava
PS: 能够先看这个博客了解下Spring Import 三种用法与源码解读web
ConfigurationClassParser的processImports方法是最核心的方法spring
// 这里是从SourceClass得到imports注解,注意jdk8容许标记多个注解,一个class能够标记多个不一样注解,其余注解上也能够标记imports注解,因此须要一个set存放 private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<>(); Set<SourceClass> visited = new LinkedHashSet<>(); collectImports(sourceClass, imports, visited); return imports; } private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates,boolean checkForCircularImports) throws IOException { if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { // 看注解里面的类是否是ImportSelector的实现类 if (candidate.isAssignable(ImportSelector.class)) { Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); invokeAwareMethods(selector); // 判断是不是须要延迟加载,继承DeferredImportSelector类的都会延迟加载 if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { // 执行ImportSelector的实现类,返回须要加载的内容 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // 这个是很是重要的,ImportBeanDefinitionRegistrar.addImportBeanDefinitionRegistrar方法的形参是registrar。 Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar =BeanUtils.instantiateClass(candidateClass,ImportBeanDefinitionRegistrar.class); invokeAwareMethods(registrar); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // 若是都不是,就调动processConfigurationClass(迭代了,processImports上两级的调用就是 processConfigurationClass) this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Exception ex) { throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
看ImportSelector.selectImports 就知道返回一个字符串数组,字符串数组是class的彻底限定名,进行processImports扫描数组
public interface ImportSelector { String[] selectImports(AnnotationMetadata importingClassMetadata); } String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false);
ImportBeanDefinitionRegistrar的重要行比ImportSelector高,最重要的是形参 BeanDefinitionRegistry,从下面代码BeanPostProcessorsRegistrar对象能够看 到,ImportBeanDefinitionRegistrar具有向容器里面注册bean的能力。能够添加想要的bean,完成想要的功能。ide
public interface ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry); } public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware { private ConfigurableListableBeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { if (beanFactory instanceof ConfigurableListableBeanFactory) { this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } } public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) { if (this.beanFactory == null) { return; } registerSyntheticBeanIfMissing(registry,"webServerFactoryCustomizerBeanPostProcessor",WebServerFactoryCustomizerBeanPostProcessor.class); registerSyntheticBeanIfMissing(registry,"errorPageRegistrarBeanPostProcessor",ErrorPageRegistrarBeanPostProcessor.class); } private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,String name, Class<?> beanClass) { if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name, beanDefinition); } } }
获得ImportBeanDefinitionRegistrar不会当即执行,会保存到一个集合中,一块儿执行this
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); invokeAwareMethods(registrar); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) { this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata); }
执行时机,是等待因此初始化的注解或者class解析完成 .net
ConfigurationClassPostProcessor对象只会被执行一次,此次只会解析那些内容。请看下面的代码,只会解析UserConsumeApplication.class的全部注解,因此有一些imports注解是不会被扫描,执行到的。本身也被坑过一次,觉得本身的imports会被扫描而且执行,搞了很久,真坑啊。code
@SpringBootApplication public class UserConsumeApplication { public static void main(String[] args) { SpringApplication.run(UserConsumeApplication.class, args); } }
#######对象
坐在一个很小的公园的花坛上写完。blog