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