ImportSelector
ImportSelector接口是Spring导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功
能性注解)中起到了决定性的作用。当在@Configuration标注的Class上使用@Import引入了一个
ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean。
DeferredImportSelector接口继承ImportSelector,他和ImportSelector的区别在于装载bean的时机
上,DeferredImportSelector需要等所有的@Configuration都执行完毕后才会进行装载
这个在我之前的博客也有写道:https://www.cnblogs.com/dalianpai/p/11722850.html
下面就写一个它的流程:
1)定义Bean对象
/** * bean对象 */ @Data public class User { private String username; private Integer age; }
2)定义配置类Configuration
/** * 没有spring注解 */ public class UserConfiguration { @Bean public User getUser() { User user = new User(); user.setAge(12); user.setUsername("阿黄"); return user; } }
3 ) 定义ImportSelector
public class UserImportSelector implements ImportSelector { //@Configuration public String[] selectImports(AnnotationMetadata annotationMetadata) { //获取配置类的名称 return new String[]{UserConfiguration.class.getName()}; } }
4) 定义EnableXXX注解
@Retention(RetentionPolicy.RUNTIME) @Documented @Target(ElementType.TYPE) @Import(UserImportSelector.class) public @interface EnableUserBean { }
5 ) 测试
@EnableUserBean public class TestApplication { /** * --> EnableUserBean --> UserImportSelector --> UserConfiguration --> User * @param args */ public static void main(String[] args) { //获取spring容器 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestApplication.class); User bean = ac.getBean(User.class); System.out.println(bean); } }
由此可见,HelloWorldConfiguration对象并没有使用Spring的对象对象创建注解声明
(@Controller,@Service,@Repostiroty),而是使用编程的方式动态的载入bean。
我们可以来看一下ConfigurationClassParser这个类的processImports方法。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, CollectionimportCandidates, boolean checkForCircularImports) { if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }