spring aop实现 -- 未完待续

a 一. AOP介绍

 AOP(Aspect Oriented Programming) 面向切面编程, 是OOP(Object Oriented Programming)面向对象编程的 补充,是一种思想。 OOP的特性(封装,继承,多态,抽象),主要强调的 对象或者类之间的纵向关系, 而横向关系却无法得到确保。 AOP正是补充的横向关系。

     一个非常简单的小例子,例如我们当前有三个类(User,Admin,Employee),都有findOne查询, 我们需要统计查询消耗的时间,在只有OOP的时候,我们就要这么写(如下图)。  亦或是根据继承,可以自行在BaseService里封装两个方法,一个beforeExecute(),一个afterExecute(), 执行时候换成 super.beforeExecute()和 super.afterExecute()。大同小异。  

import ..... // 省略
  
@Service
public class AdminService extends BaseService{
  @Resource
  private AdminDAO adminDAO;
  
  // Slf4j日志
  private final Logger logger = LoggerFactory.getLogger(ScheduledService.class);
  
  public Admin findOne() {
     logger.info("查询开始了" + System.currentTimeMillis());
     return adminDAO.findOne(); // "SELECT * FROM admin limit 1"
     logger.info("查询结束了" + System.currentTimeMillis());
  }
}

Employee和User同理,不重复了

可以看到,每一个实现最起码要调用一次,(大项目成百上千的model,service),重复量就很大, 如果是想修改其中的逻辑,就需要每一个都修改一次,重复工作量很大。

   AOP利用 "横切"思想,横向扩展类,并将公共行为封装到一起(所谓的Aspect,切面),减少系统的重复代码,降低模块之间的耦合度,提升可维护度。   二. AOP一些常用概念

   1. advice : 直译 为 "增强",或者"通知"。 是aop执行的具体逻辑操作, spring定义了 前置(beforeAdvice),后置(afterAdvice),异常(ThrowsAdvice),引入(DynamicIntroductionAdvice)四种,具体目录为org.springframework.aop。 需要注意的是, 第五种, 环绕(AspectJAroundAdvice)不是spring定义的,而是AspectJ定义的,具体路径为org.springframework.aop.aspectj。 

   2. join point : 连接点。 是在逻辑执行时可插入切面的一个点。这个点可以是调用方法时、抛出异常时或者其他行为。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

   3. pointcut : 切点。切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是通过表达式匹配的一组类或方法。

 关于切点和连接点,查资料查的我一度非常混淆这两个甚至觉得这就是一个概念。 在官方搜索的一个小博客里,看到了这样一句话 "pointcut that allows selecting join points in beans with a matching name pattern". 大概我自己的理解就是 切点一定是连接点,而连接点不一定是切点。

   4.aspect : 切面。 是一个大的概念,切面应该是pointcut + advice ,是一个整体的东西。

   5.weaving : 织入。 构建新对象(代理对象)的方法,spring选择在运行时动态注入,而aspectj选择在编译器或者类装载时,根据类的修饰决定是jdk代理还是cglib代理。一般都是由ProxyFactory来完成

  总的来说,AOP通过切点进行织入, 通过代理的方式构造出代理对象,来替代原对象进行逻辑的执行。

三. aop的源码分析

   使用过springboot的童鞋们都知道,利用注解@EnableAspectJAutoProxy则可以开启aop模式(记得加载aop的jar包)。 而早些版本的spring则需要在xml文件中配置 <aop:config>或者是<aop:aspectj-autoproxy>来开启。

   我们从@EnableAspectJAutoProxy 追溯进去,到达注解类的源码。

package org.springframework.context.annotation; // 具体的包位置 有兴趣的可以看看

import ...// import省略


@Target({ElementType.TYPE}) // 元注解之一, 表示该注解的修饰范围
@Retention(RetentionPolicy.RUNTIME) // 元注解之一, 表示该类保留的阶段
@Documented // 元注解之一,标记为公众api,可以javadoc文档话
@Import({AspectJAutoProxyRegistrar.class}) //  导入注解,类似于组合,将参数类(可以为多个)注入到当前容器中
public @interface EnableAspectJAutoProxy {
    // 代理类标志,为true代表直接代理类,需要利用cglib代理。 为false则直接使用传统的jdk代理方式
    boolean proxyTargetClass() default false;

    // 是否将该代理对象暴露为线程共享,为true则暴露,使用threadLocal方式,为false则忽略
    boolean exposeProxy() default false;
}

      ps: 关于元注解,其实是修饰注解的注解,大概所有@Enable开头的注解类都有这几个修饰。 可以参考这篇文章 : java元注解

      ps_2: 关于@Import,个人更容易理解为组合的模式,没有继承或者实现的关系,更像是一种内部类的感觉,类似于php的trait,或是python的imp.load_source。

   看一下AspectJAutoProxyRegisterar的源码,发现只有一个方法

package org.springframework.context.annotation;

import ... // import省略

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    AspectJAutoProxyRegistrar() {
    }

    /*
     *  @param AnnotationMetadata  导入数据的配置类
     *  @param BeanDefinitionRegistry 一种bean的定义格式,包含一些注册的接口,通常为beanFactory
     */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
     
     // 注册成spring使用的beanDefinition格式 --- 1
     AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

     // 将配置数据注册到  AnnotationAttributes格式(封装的特殊map) 的属性列表
     AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, 
     EnableAspectJAutoProxy.class);
        // 判断配置数据的map
        if (enableAspectJAutoProxy != null) {
            // 判断对应的属性值(该属性值上文已讲), 为true则直接使用cglib代理 ---2
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            // 判断对应的属性值(该属性值上文已讲), 为true则直接使用暴露性接口 ---3
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }

    }
}

重点就是 1的方法,注册成beanDefinitition,包含了整体的核心逻辑。 其中 最重要的则是被调用的重载方法, 将一个很核心的类AnnotationAwareAspectJAutoProxyCreator注入。 

public abstract class AopConfigUtils {
    //外部调用的注册方法,实际调用的是内部对应的重载方法
    @Nullable // 参数可为null的注解
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
        return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, (Object)null);
    }

    // 被调用的重载方法,此步是重点
    @Nullable
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
       // 在此地方注入AnnotationAwareAspectJAutoProxyCreator 这个类,是aop的关键类
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }

    // 执行注册
    @Nullable
    private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

        // 实际注册的org.springframework.aop.config.internalAutoProxyCreator
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            // 获取internalAutoProxyCreator的定义
            BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            // 与我们传入的类名做对比, 如果一致则不做处理。 如果不一致,则需要决定优先级问题
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                // 获取优先级并进行对比
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    // 优先级被更高的取代时, 设置beanClassName。 定义的名称,不等同于最终的beanName
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }

            return null;
        } else {
            // else分支表示目前没有internalAutoProxyCreator的定义,则直接新建
            RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
            beanDefinition.setSource(source);
            beanDefinition.getPropertyValues().add("order", -2147483648);
            beanDefinition.setRole(2);
            // 注册定义
            registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
            return beanDefinition;
        }
    }
}

    // 优先级队列获取,可以看到,这个类维护了一个优先级的数组,使用static代码块进行初始化,越靠后的优先级就越高
    // 直接根据index的索引定优先级也是很暴力的操作。
    private static int findPriorityForClass(Class<?> clazz) {
        return APC_PRIORITY_LIST.indexOf(clazz);
    }
    
    // 静态代码块初始化
    static {
        APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    }

   补充一点 : 在registerOrEscalateApcAsRequired方法中 注册了"org.springframework.aop.config.internalAutoProxyCreator"这个类。查了一些资料没有什么有价值的, 我翻了一下老版本的源码的发现是个预定义的常量,名为"AUTO_PROXY_CREATOR_BEAN_NAME"。  然而 "org.springframework.aop.config.internalAutoProxyCreator"只是BeanDefintion的定义的className而已,并非真的类名.其对应的真实类是org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator。 具体在哪里进行的alias别名没有找到,暂时留一个坑吧。

   如果通读这段逻辑会发现,我们明明注册的是"AnnotationAwareAspectJAutoProxyCreator",在首次进入的时候,却直接注册"org.springframework.aop.config.internalAutoProxyCreator"。(第一个if判断的时候已经走的else)

   我打开了AnnotationAwareAspectJAutoProxyCreator类的继承图,说明先注册的是父类,所以并没有什么问题,但是具体为什么这么设计就不得而知了。即使再次注册到子类也会因为优先级的原因,将类变为对应的子类。

   继而我们可以继续分析其源码,打开AnnotationAwareAspectJAutoProxyCreator,发现只有简单的几个属性和一些setter。 

<--插播一些spring bean生命周期的知识-->  bean在初始化时一般会执行 

postProcessBeforeInstantiation()  -> constructor() -> postProcessPropertyValues() 这几步,而代理对象一般也在这三步中产生。所以我们向上查找直到AbstractAutoProxyCreator 。 找到了postProcessBeforeInstantiation()方法

查看AbstractAutoProxyCreator的postProcessBeforeInstantiation方法。 AbstractAutoProxyCreator定义许多属性,有数组,map甚至bool来辅助记录各种状态的bean,方便后续使用,不贴这部分的代码了,有兴趣可以去看一下

// AbstractAutoProxyCreator.class


public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 拿取缓存的key
        Object cacheKey = this.getCacheKey(beanClass, beanName);
        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            // 如果是增强类。直接忽略
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            // 判断 特殊bean,判断是否和切面、切点bean等 aop相关类或实现其接口的类
            // shouldSkip则判断是否是 original类,也就是原始类
            if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
                // 则直接放入属性advisedBeans(concurrentHashMap)中, 并打上对应的tag,标记其为特殊类
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
        // 判断自定义的targetSource方法
        TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
        // 如果有自定义target方法则加入对应的属性(map)中
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }
            // 获取增强的方法 --- 重点1
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            // 创建代理对象 --- 重点2
            Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
            // 将对象标记并存入自身属性(Map)中
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            return null;
        }
    }
上述比较重要的方法就是获取对应的增强getAdvicesAndAdvisorsForBean()方法,和 获取代理对象的方法 createProxy()。会发现AbstractAutoProxyCreator的getAdvicesAndAdvisorsForBean()是个抽象方法,交由子类实现。 实现地点在子类AbstractAdvisorAutoProxyCreator中(上述类图的第一个子类)
// AbstractAdvisorAutoProxyCreator.class
    
    @Nullable
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        // 获取 对应beanClass的所有增强
        List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
        // DO_NOT_PROXY是一个空数组常量。 如果找不到则返回空数组,否则返回转到数组状态的增强类
        return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
    }

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        // 寻找目前所有的增强类
        List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
        // 所有增强类进行处理,筛选 来确定使用的
        List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        // 将增强加入对应的属性
        this.extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) { // 进行一下排序
            eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
        }

        return eligibleAdvisors;
    }

   findCandidateAdvisors由子类进行了实现,扩展了父类的该方法。  算法还是有些复杂的,整体流程还是比较干净清晰的。大概流程就是通过递归方式遍历所有的bean,如果有@Aspect修饰就加入到数组中进行标记。

// AnnotationAwareAspectJAutoProxyCreator.class
protected List<Advisor> findCandidateAdvisors() {
        // 调用的实际是 父类的方法
        List<Advisor> advisors = super.findCandidateAdvisors();
        // 扩展后续的逻辑
        if (this.aspectJAdvisorsBuilder != null) {
             // 寻找所有注解为@ASpect的增强类
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }

        return advisors;
}


// org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.class

// 寻找注解为@Aspect的增强器,包含父类的递归查询 
public List<Advisor> buildAspectJAdvisors() {
        // 所有的增强类
        List<String> aspectNames = this.aspectBeanNames;
        if (aspectNames == null) {
            synchronized(this) {
                aspectNames = this.aspectBeanNames;
                // 如果还没定义切面的beanName
                if (aspectNames == null) {
                    List<Advisor> advisors = new ArrayList();
                    List<String> aspectNames = new ArrayList();
                    // 递归方法,从下到上查找所有的bean,
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
                    String[] var18 = beanNames;
                    int var19 = beanNames.length;

                    for(int var7 = 0; var7 < var19; ++var7) {
                        String beanName = var18[var7];
                        // isEligibleBean交由实现类实现,判断一些类的条件,当前类默认返回true
                        if (this.isEligibleBean(beanName)) {
                            // 直接从beanFactory拿对应的bean
                            Class<?> beanType = this.beanFactory.getType(beanName);
                            // isAspect()判断该bean是否由 @Aspect注解 有则返回true                            
if (beanType != null && this.advisorFactory.isAspect(beanType)) {
                                // 加入数组中
                                aspectNames.add(beanName);
                                // 创建一个AspectMetadata类(Aspect注解类的实例化模型),判断是否为Aspect的实现。 一层一层的遍历,从子找到父, 直到找到不为Object子类的 Aspect对象
                                AspectMetadata amd = new AspectMetadata(beanType, beanName);
                                // 判断切面的实例模式 -- 后边会引入文章介绍
                                if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                    // 创建Aspect的元数据
                                    MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                    // 通过反射,获取该增强内所有的方法
                                    List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                    // 对应不同的模式 进行不同的标记处理
                                    if (this.beanFactory.isSingleton(beanName)) {
                                        this.advisorsCache.put(beanName, classAdvisors);
                                    } else {
                                        this.aspectFactoryCache.put(beanName, factory);
                                    }
                                    // 将获取到的增强加入List中
                                    advisors.addAll(classAdvisors);
                                } else {
                                    if (this.beanFactory.isSingleton(beanName)) {
                                        throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton");
                                    }
                                    // 非单例模式的方法, 直接加入对应的工厂中和数组中,
                                    MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                                    this.aspectFactoryCache.put(beanName, factory);
                                    advisors.addAll(this.advisorFactory.getAdvisors(factory));
                                }
                            }
                        }
                    }

                    this.aspectBeanNames = aspectNames;
                    return advisors;
                }
            }
        }
        // 应对aspectName数组不为空的时候
        if (aspectNames.isEmpty()) {
            return Collections.emptyList();
        } else {
            // 通过迭代的方法,直接遍历当前的aspectName
            List<Advisor> advisors = new ArrayList();
            Iterator var3 = aspectNames.iterator();
  
            while(var3.hasNext()) {
                String aspectName = (String)var3.next();
                List<Advisor> cachedAdvisors = (List)this.advisorsCache.get(aspectName);
                // 在Cache的查找 如果没有则新建 和上述操作差不多
                if (cachedAdvisors != null) {
                    advisors.addAll(cachedAdvisors);
                } else {
                    MetadataAwareAspectInstanceFactory factory = (MetadataAwareAspectInstanceFactory)this.aspectFactoryCache.get(aspectName);
                    advisors.addAll(this.advisorFactory.getAdvisors(factory));
                }
            }

            return advisors;
        }
}


// org.springframework.beans.factory.BeanFactoryUtils.class

// 通过递归的方法 从下之上搜索拿去所有的bean
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        Assert.notNull(lbf, "ListableBeanFactory must not be null");
        String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
        if (lbf instanceof HierarchicalBeanFactory) {
            HierarchicalBeanFactory hbf = (HierarchicalBeanFactory)lbf;
            if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
                // 递归的拿取父节点
                String[] parentResult = beanNamesForTypeIncludingAncestors((ListableBeanFactory)hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
                result = mergeNamesWithParent(result, parentResult, hbf);
            }
        }

        return result;
}

 关于amd.getAjType().getPerClause().getKind(). 其实是Aspect的AspectMetadata类提供的一些方式,目前有四种,默认为singleton(和spring一样的单例),其他的三种是pertarget、perthis、pertypewithin。找到这么一篇帖子, 实例化切面模式 

 

// todo

 后面继续写 

findAdvisorsThatCanApply

和 getProxy....

 

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值