基于ImportSelector模拟简单的Aop

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去掉,则不会再执行代理方法:

基于ImportSelector模拟简单的Aop

 

上一篇:mapstruct 1.4.2和lombok 1.18.16之后版本,报错和mapstruct生成空的实现


下一篇:你还在使用 BeanUtils 来做对象转换吗?快试试 MapStruct 吧!