@Import注解的作用
作者:互联网
在@Import注解的参数中可以填写类名,例如@Import(Abc.class),根据类Abc的不同类型,spring容器有以下四种处理方式:
- 1. 如果Abc类实现了ImportSelector接口,spring容器就会实例化Abc类,并且调用其selectImports方法;
- 2. DeferredImportSelector是ImportSelector的子类,如果Abc类实现了DeferredImportSelector接口,spring容器就会实例化Abc类,并且调用其selectImports方法,和ImportSelector的实例不同的是,DeferredImportSelector的实例的selectImports方法调用时机晚于ImportSelector的实例,要等到@Configuration注解中相关的业务全部都处理完了才会调用(具体逻辑在ConfigurationClassParser.processDeferredImportSelectors方法中),想了解更多DeferredImportSelector和ImportSelector的区别,请参考《ImportSelector与DeferredImportSelector的区别(spring4) 》;
- 3. 如果Abc类实现了ImportBeanDefinitionRegistrar接口,spring容器就会实例化Abc类,并且调用其registerBeanDefinitions方法;
- 4. 如果Abc没有实现ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar等其中的任何一个,spring容器就会实例化Abc类,官方说明在这里;
spring源码版本:5.0.5.RELEASE
跟踪spring容器是如何处理Import注解的,容器初始化一般从AbstractApplicationContext类的refresh开始,其它过程跳过,直接通过堆栈到相关的地方;
doProcessConfigurationClass:300, ConfigurationClassParser {org.springframework.context.annotation} processConfigurationClass:245, ConfigurationClassParser {org.springframework.context.annotation} parse:194, ConfigurationClassParser {org.springframework.context.annotation} doProcessConfigurationClass:293, ConfigurationClassParser {org.springframework.context.annotation} processConfigurationClass:245, ConfigurationClassParser {org.springframework.context.annotation} parse:202, ConfigurationClassParser {org.springframework.context.annotation} parse:170, ConfigurationClassParser {org.springframework.context.annotation} processConfigBeanDefinitions:316, ConfigurationClassPostProcessor {org.springframework.context.annotation} postProcessBeanDefinitionRegistry:233, ConfigurationClassPostProcessor {org.springframework.context.annotation} invokeBeanDefinitionRegistryPostProcessors:273, PostProcessorRegistrationDelegate {org.springframework.context.support} invokeBeanFactoryPostProcessors:93, PostProcessorRegistrationDelegate {org.springframework.context.support} invokeBeanFactoryPostProcessors:694, AbstractApplicationContext {org.springframework.context.support} refresh:532, AbstractApplicationContext {org.springframework.context.support}
ConfigurationClassParser是解析@PropertySources,@ComponentScan,@Import,@ImportResource,@Bean注解的地方
在ConfigurationClassParser#parse中
public void parse(Set<BeanDefinitionHolder> configCandidates) { //稍后执行的parse方法中,所有DeferredImportSelector实现类都会被放入集合deferredImportSelectors中 this.deferredImportSelectors = new LinkedList<>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { //在这个parse方法中,所有DeferredImportSelector实现类都会被放入集合deferredImportSelectors中,它们的selectImports方法不会被执行,而其他ImportSelector实现类的selectImports都会被执行 parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } //此方法内,会将集合deferredImportSelectors中的所有对象取出来执行其selectImports方法 processDeferredImportSelectors(); }
查看处理@import的地方
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { ...... // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), true); ...... }
跟踪查看getImports就是递归取类的@Import注解的,取到后在processImports方法中进行处理:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, 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) { //如果是ImportSelector接口的实现类,就在此处理 if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); //实例化这些ImportSelector的实现类 ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); //如果这实现类还实现了BeanFactoryAware、EnvironmentAware这些接口,就要先执行这些接口中声明的方法 ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); //如果这个实现类也实现了DeferredImportSelector接口,就被加入到集合deferredImportSelectors中,在解析完成后在执行 if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { //注意,这一行是关键代码!!!执行实现类的selectImports方法 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } //处理ImportBeanDefinitionRegistrar的实现类 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(); } } }
小结如下:
- 1. 普通类(即没有实现ImportBeanDefinitionRegistrar、ImportSelector、DeferredImportSelector等接口的类)会通过ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources方法将bean定义注册到spring容器;
- 2. ImportSelector实现类,其selectImports方法返回的bean的名称,通过ConfigurationClassParser类的asSourceClass方法转成SourceClass对象,然后被当作普通类处理;
- 3. ImportSelector与DeferredImportSelector的区别,就是selectImports方法执行时机有差别,这个差别期间,spring容器对此Configguration类做了些其他的逻辑:包括对@ImportResource、@Bean这些注解的处理(注意,这里只是对@Bean修饰的方法的处理,并不是立即调用@Bean修饰的方法,这个区别很重要!);
- 4. ImportBeanDefinitionRegistrar实现类的registerBeanDefinitions方法会被调用,里面可以注册业务所需的bean定义;
标签:DeferredImportSelector,springframework,ImportSelector,context,org,Import,注解,作用,C 来源: https://www.cnblogs.com/grasp/p/11906642.html