Spring注解之@Import使用方法讲解
程序员小潘 人气:01. 前言
Spring提供了@Import
注解,用于向容器引入我们自定义的类,在许多注解中我们都会看到它的身影,比如MyBatis在整合Spring时,提供的@MapperScan
注解:
@Import(MapperScannerRegistrar.class) public @interface MapperScan { }
比如Spring开启AOP功能的注解:
@Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { }
再比如Spring的异步调用注解:
@Import(AsyncConfigurationSelector.class) public @interface EnableAsync { }
大部分@Enable***
注解的原理都差不多,都是通过利用@Import
注解向Spring容器注入一些bean来实现的。
2. 用法
@Import
注解可以引入三种类。
1、引入普通类,将作为bean注册到Spring容器。
@Configuration @Import(Person.class) public class Application { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(Application.class); Person person = context.getBean(Person.class); } }
2、引入ImportSelector实现类,Spring会将**selectImports()**
方法返回的bean数组注册到Spring容器,但是ImportSelector对象本身不会注册到容器。
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.javap.importt.Person"}; } }
3、引入ImportBeanDefinitionRegistrar实现类,Spring会暴露 BeanDefinitionRegistry对象,你可以自由的往容器里面注册BeanDefinition,但是ImportBeanDefinitionRegistrar对象本身不会注册到容器。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 往registry注册BeanDefinition } }
MyBatis整合Spring时,提供的@MapperScan
注解引入的就是ImportBeanDefinitionRegistrar的实现类,MyBatis会去扫描指定的包路径,然后将Mapper接口对应的BeanDefinition注册到容器里。
3. 源码分析
解析类上的@Import
注解的职责Spring交给了ConfigurationClassPostProcessor类,它是BeanFactoryPostProcessor的子类,也就是说它属于BeanFactory的扩展点之一,它会处理容器内所有的ConfigurationClass。
ConfigurationClassPostProcessor首先会过滤出容器内所有的ConfigurationClass,然后实例化一个ConfigurationClassParser解析器去解析ConfigurationClass,解析过程中就会处理类上的@Import
注解了,方法是ConfigurationClassParser#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) { if (candidate.isAssignable(ImportSelector.class)) { // 引入的是ImportSelector子类 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 { // 调用子类方法,得到要引入的beanNames String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // 引入的是ImportBeanDefinitionRegistrar子类 Class<?> candidateClass = candidate.loadClass(); // 实例化子类对象 ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); // 暂存到Map,稍后触发 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // 引入的是普通类,正常注入到容器 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); // 引入的类可能是ConfigurationClass,递归处理 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(); } } }
方法做了三件事:
- 如果引入的是ImportSelector子类,实例化子类对象,调用
selectImports()
方法得到要注册的beanNames,完成注册。 - 如果引入的是ImportBeanDefinitionRegistrar子类,实例化子类对象,暂存到Map,稍后触发。
- 如果引入的是普通类,正常注册到容器。
对于ImportBeanDefinitionRegistrar子类,这里只是实例化了子类对象然后暂存到Map容器中,此时还没有去触发ImportBeanDefinitionRegistrar#registerBeanDefinitions()
方法。方法的触发是在ConfigurationClass解析完以后,ConfigurationClassPostProcessor会调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars()
方法遍历Map容器中所有的ImportBeanDefinitionRegistrar子类对象,挨个触发扩展方法。
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry)); }
加载全部内容