转发请注明出处:
@Import通过快速导入的方式实现把实例加入spring的IOC容器中;一般@EnableXXX注解是通过@Import实现具体的功能(@EnableXXX注解上加个@Import注解),@Import才是@EnableXXX起效果的核心功能。
Import 注解实现过程在 ConfigurationClassParser 中的 processImports 方法:
// 解析@Import注解 private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { if (!importCandidates.isEmpty()) { if (checkForCircularImports && this.isChainedImportOnStack(configClass)) { this.problemReporter.error(new ConfigurationClassParser.CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { Iterator var6 = importCandidates.iterator(); while(var6.hasNext()) { ConfigurationClassParser.SourceClass candidate = (ConfigurationClassParser.SourceClass)var6.next(); Class candidateClass; // 判断是否实现了ImportSelector.class;ImportSelector接口的作用其实就是往spring容器中再次注入一批配置类。 if (candidate.isAssignable(ImportSelector.class)) { candidateClass = candidate.loadClass(); ImportSelector selector = (ImportSelector)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<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames, exclusionFilter); this.processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // 判断是否实现了 ImportBeanDefinitionRegistrar 类 candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = (ImportBeanDefinitionRegistrar)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()); this.processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } } catch (BeanDefinitionStoreException var17) { throw var17; } catch (Throwable var18) { throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", var18); } finally { this.importStack.pop(); } } } }
首先判断@Import注解导入的是配置类有没有实现ImportSelector接口,实现的话就就调用ImportSelector的selectImports方法,这个方法返回的是一批配置类的全限定名,然后继续解析这些配置类。
ImportSelector接口的作用其实就是往spring容器中再次注入一批配置类。
如果没有实现ImportSelector接口,那么再判断有没有实现ImportBeanDefinitionRegistrar,有的话就会调用ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,通过名字也可以判断出,其实就是往spring容器注入一些BeanDefinition。
@Import 注解实现类的bean 注册过程接口
public interface ImportBeanDefinitionRegistrar { default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { this.registerBeanDefinitions(importingClassMetadata, registry); } default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }
ImportBeanDefinitionRegistrar的作用其实很简单,就是往spring容器注入一些BeanDefinition。
总结@Import的作用:
@Import注解,就是导入一个配置类,但是这个配置类分为不同的情况。如果这个配置类实现了ImportSelector接口,那么就会调用selectImports方法的实现,获取一批配置类的全限定名,然后再解析配置类;如果实现了@Import注解导入的配置类实现类ImportBeanDefinitionRegistrar,那么就会调用registerBeanDefinitions方法的实现,这个方法可以往容器中注入BeanDefinition;最后如果都没实现,那么就按照一个普通的配置类来解析。
所以基于这么一套配置类解析的规则,就可以实现往容器中注入一些bean,通过这些bean来完成某块功能的实现。
可以看看 @EnableDiscoveryClient 和 @EnableFeignClients 两个注解的定义
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({EnableDiscoveryClientImportSelector.class}) public @interface EnableDiscoveryClient { boolean autoRegister() default true; }
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Import({FeignClientsRegistrar.class}) public @interface EnableFeignClients { String[] value() default {}; String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] defaultConfiguration() default {}; Class<?>[] clients() default {}; }
标签: spring boot