Spring Framework自3.1开始,支持“@Enable 模块驱动”。其意义在于能够简化装配步骤,实现“按需装配”,同时屏蔽组件集合装配的细节。Spring Framework在实现上分为两类:“注解驱动 ”和“接口编程 ”。两种实现均需要依赖@Import,其职责是导入一个或多个组件类( component classes  ),将其定义为Spring Bean。 这里的组件类分两种:
被标注@Configuration的类;普通的组件类,作用类似AnnotationConfigApplicationContext#register(对应注解驱动) 
ImportSelector或者ImportBeanDefinitionRegistrar接口的实现类(对应接口编程)。 
 
基于”注解驱动” @EnableWebMvc注解是基于“注解驱动”的例子:
1 2 3 4 5 6 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebMvcConfiguration.class) public  @interface  EnableWebMvc {} 
 
1 2 3 @Configuration(proxyBeanMethods = false) public  class  DelegatingWebMvcConfiguration  extends  WebMvcConfigurationSupport   {} 
 
基于“接口编程” 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public  interface  ImportSelector   {	String[] selectImports(AnnotationMetadata importingClassMetadata); 	@Nullable  	default  Predicate<String> getExclusionFilter ()   { 		return  null ; 	} } 
 
ImportSelector接口的作用是判断哪些被@Configuration标注的类应该被导入,判断条件一般是一个或多个注解属性。ImportSelector接口定义了一个selectImports 方法,返回需要被导入的类的全称限定名。入参是正在被导入的@Configuration类的AnnotationMetadata。这里正在被导入的@Configuration类是指@Import标注的类,在“**@Enable 模块驱动”中指被 @Enable**标注的类。
1 2 3 4 5 6 7 8 9 10 public  interface  ImportBeanDefinitionRegistrar   {	default  void  registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,  			BeanNameGenerator importBeanNameGenerator)   {		registerBeanDefinitions(importingClassMetadata, registry); 	}      	default  void  registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)   { 	} } 
 
ImportBeanDefinitionRegistrar接口相对于ImportSelector而言,多了一个BeanDefinitionRegistry,作为入参,将Bean定义(BeanDefinition)的注册也交给了开发人员。
@Enable模块驱动原理         在Spring应用上下文启动过程中(AbstractApplicationContext#refresh()方法被调用时),Spring容器(BeanFactory)将ConfigurationClassPostProcessor 初始化为Spring Bean,作为优先级最高的BeanFactoryPostProcessor实现,随后其postProcessBeanFactory方法被调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public  void  postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory)   {		int  factoryId = System.identityHashCode(beanFactory); 		if  (this .factoriesPostProcessed.contains(factoryId)) { 			throw  new  IllegalStateException( 					"postProcessBeanFactory already called on this post-processor against "  + beanFactory); 		} 		this .factoriesPostProcessed.add(factoryId); 		if  (!this .registriesPostProcessed.contains(factoryId)) { 			 			 			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); 		} 		enhanceConfigurationClasses(beanFactory); 		beanFactory.addBeanPostProcessor(new  ImportAwareBeanPostProcessor(beanFactory)); } 
 
列一下processConfigBeanDefinitions主要的步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  void  processConfigBeanDefinitions (BeanDefinitionRegistry registry)   {		List<BeanDefinitionHolder> configCandidates = new  ArrayList<>(); 		String[] candidateNames = registry.getBeanDefinitionNames(); 		 		for  (String beanName : candidateNames) { 			BeanDefinition beanDef = registry.getBeanDefinition(beanName); 			... 			 			else  if  (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this .metadataReaderFactory)) { 				configCandidates.add(new  BeanDefinitionHolder(beanDef, beanName)); 			} 		}     	...          		ConfigurationClassParser parser = new  ConfigurationClassParser( 				this .metadataReaderFactory, this .problemReporter, this .environment, 				this .resourceLoader, this .componentScanBeanNameGenerator, registry);     	...     	Set<BeanDefinitionHolder> candidates = new  LinkedHashSet<>(configCandidates);     	...         parser.parse(candidates);     	... } 
 
parse方法将@Configuration类包装为ConfigurationClass,然后调用processConfigurationClass方法。
1 2 3 4 5 6 7 8 9 10 11 protected  void  processConfigurationClass (ConfigurationClass configClass, Predicate<String> filter)  throws  IOException  {		... 		 		SourceClass sourceClass = asSourceClass(configClass, filter); 		do  { 			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); 		} 		while  (sourceClass != null ); 		this .configurationClasses.put(configClass, configClass); 	} 
 
processConfigurationClass方法又调用了doProcessConfigurationClass进行处理。doProcessConfigurationClass方法会处理很多注解,例如@Component、@PropertySource、@ComponentScan、@Bean方法等。我们这里只关注对@Import注解的处理方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 processImports(configClass, sourceClass, getImports(sourceClass), filter, true ); private  void  processImports (ConfigurationClass configClass, SourceClass currentSourceClass, 			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, 			boolean  checkForCircularImports)   {    ...     for  (SourceClass candidate : importCandidates) { 					if  (candidate.isAssignable(ImportSelector.class)) { 						 						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 ); 						} 					} 					else  if  (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { 						 						 						Class<?> candidateClass = candidate.loadClass(); 						ImportBeanDefinitionRegistrar registrar = 								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, 										this .environment, this .resourceLoader, this .registry); 						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); 					} 					else  { 						 						 						this .importStack.registerImport( 								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); 						processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); 					} 				} } 
 
可以看到processImports 方法会处理ImportSelector实现、ImportBeanDefinitionRegistrar实现,其他情况会视为@Configuration类,再调用回processConfigurationClass 方法。最后ConfigurationClass集合将被注册为Spring Bean。
ConfigurationClassPostProcessor 不仅检查@Configuration和@Bean两种Bean定义方式,还处理@Component。@Configuration类标注为“完全模式”,而@Component和@Bean方法则是“轻量模式”。最后使用CGLib实现ConfigurationClassEnhancer对@Configuration类进行提升。
综上所述,ConfigurationClassPostProcessor 负责筛选@Component类、@Configuration类及@Bean方法的BeanDefinition,ConfigurationClassParser 则从候选的Bean定义中解析出ConfigurationClass集合并注册成Spring Bean。