ImportSelector接口是至spring中导入外部配置类的核心接口,基于它可以实现以开关的模式开启某个功能,在SpringBoot中可以看到大量的注解@EnableXXX,点进去发现都有ImportSelector的存在。
Spring解析@Import源码分析
Spring在解析配置类的时候,针对Import的处理如下:
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 selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); s); //如果该接口的实现类同时实现EnvironmentAware, BeanFactoryAware ,BeanClassLoaderAware或者ResourceLoaderAware,那么在调用其selectImports方法之前先调用上述接口中对应的方法 ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); //如果是deferredImportSelectors类型,代表需要延时处理,先暂时放到List<DeferredImportSelectorHolder> deferredImportSelectors中,等到所有的@Configuration处理完,最后面才处理实现了DeferredImportSelector接口的类 if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { 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(); } }
针对ImportSelector的处理:实例化了其对象:
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
然后调用其方法:selector.selectImports()得到类名,其最终会根据相关的类生成BeanDefinition对象并实例化bean加入到beanMap中去。由此基于ImportSelector我们可以做一个动态的Aop并通过开关进行控制,其实SpringAop大概也是这么实现的。
模拟实现SpringAop
定义一个接口
public interface IUserDao { void query(); }
定义一个实现类
@Repository public class UserDao implements IUserDao { public void query() { System.out.println("from db....."); } }
Aop代理实现
public class MyAop implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("userDao")) { bean = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{IUserDao.class}, new MyInvokeHandler(bean)); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } } public class MyInvokeHandler implements InvocationHandler { Object target; public MyInvokeHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy 方法"); return method.invoke(target, args);
定义一个开关
@Retention(RetentionPolicy.RUNTIME) @Import(MyImportSelect.class) public @interface EanableAop { }
配置类
@Configuration @ComponentScan("com.tian") @EanableAop public class AppConfig {}
测试
@Test public void test_import() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); String[] names = context.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } IUserDao dao = (IUserDao) context.getBean("userDao"); dao.query(); }
最终结果,当然如果把@EanableAop去掉,则不会再执行代理方法: