• 基于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);
       }
    }

    实现ImportSelector接口

    public class MyImportSelect implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            return new String[]{com.tian.util.MyAop.class.getName() };
        }
    }

    定义一个开关

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

  • 相关阅读:
    C++类模板——博客链接
    static成员变量
    C++之++操作符重载
    运算符重载笔记
    纯虚函数(pure virtual function )和抽象类(abstract base class)
    thinkphp 无限极分类的数据库设计及效果测试
    thinkphp 对百度编辑器里的内容进行保存
    thinkphp 最简单的引入百度编辑器的方法
    thinkphp文章列表及删除文章
    thinkphp添加后台的构思以及添加数据功能
  • 原文地址:https://www.cnblogs.com/tianboblog/p/12619262.html
Copyright © 2020-2023  润新知