自己手写一个AOP动态代理框架(2)

之前实现的自己手写一个AOP动态代理框架(1)只能根据控制器,业务层,DAO层等等注解的形式来进行切面,这里仿Spring,支持AspectJ的表达式进行定位类方法资源,然后进行代理。

集成AspectJ的语法树,即复用AspecJ的对资源的定位功能。也就是说可以使用 execution(* com.fuyouj.service..*.*(..))这样的表达式。

AspectJ简介

提供了完整的AOP实现。
定义了切面语法和切面语法的解析。
Spring支持方法级别的织入(满足80%的需求了),AspectJ支持全方位多角度的切面织入。AspectJ学习成本高,所以Spring就没有完整支持所有织入。

导入AspectJ的包

 <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

AspectJ的织入时机

  1. 编译时织入:利用ajc编译器将源文件编译成class文件,并且将切面逻辑织入到java文件里面。
  2. 编译后织入::利用ajc编译器修改class文件。
  3. 类加载时织入:在类加载器加载对象的时候,将切面织入到代码里。JVM里面最终只有一个类,不同于Spring的方式,JVM里面其实时多出来了一个代理类。

从以上3点来说,理论上AspectJ的效率比Spring要高,毕竟在使用前已经准备好了。而Spring需要新生成一个代理去替换。
实际上我们的使用必须依赖于Spring的容器,容器没有初始化成功,我们就无法使用。但是容器初始化完成,必然AOP也已经完成,我们谁又哪能感受得到这个差距呢?

AOP的实现

改造Aspect注解

//作用在类上
@Target(ElementType.TYPE)
//运行时有效
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
    //删除
  //  Class<? extends Annotation> value() default DefaultAspect.class;
  //新增
    String pointCut();
}

一个提供解析表示式能力的类

/**
 * 解析Aspect表达式 并且定位被织入的目标
 */
public class PointCutLocator {
  /**
     *AspectJ的  point 解析器
     */
    //支持AspectJ的所有表达式
    private PointcutParser pointcutParser = PointcutParser
            .getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
                    PointcutParser.getAllSupportedPointcutPrimitives()
            );
    /**
     * AspectJ的表达式解析器
     */
    private PointcutExpression pointcutExpression;

    /**
     * 初始化解析表达式
     * @param expression
     */
    public PointCutLocator(String expression){
     pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    /**粗筛
     * @param targetClass
     * @return 是否匹配
     */
   public boolean roughMatches(Class<?> targetClass){
       //只能校验 withIn表达式 对于不能校验的 execution表达式,默认返回true  所以这里是粗筛
      return pointcutExpression.couldMatchJoinPointsInType(targetClass);
   }
    /**精确筛选
     *判断传入的 Method对象是否是Aspect的目标代理方法,即精确匹配PointCut
     * @param method
     * @return
     */
   public boolean accurateMatches(Method method){
       ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
       return shadowMatch.alwaysMatches();
   }
}

改写AOP

先说说思路。
1.获取容器里面所有的切面类
2.拼接好切面描述类集合
3.遍历容器的类,为符合被代理条件的类创建初筛后的集合
4.对每个类尝试织入,织入的时候精确筛选。

改造AspectInfo,支持复用AspectJ的解析能力。

@Data
public class AspectInfo {
  private int orderIndex;
  private DefaultAspect aspectObject;
  //复用AspectJ
  private PointCutLocator pointCutLocator;
  public AspectInfo() {

  }

  public AspectInfo(int orderIndex, DefaultAspect aspectObject) {
    this.orderIndex = orderIndex;
    this.aspectObject = aspectObject;
  }

  public AspectInfo(int orderIndex, DefaultAspect aspectObject, PointCutLocator pointCutLocator) {
    this.orderIndex = orderIndex;
    this.aspectObject = aspectObject;
    this.pointCutLocator = pointCutLocator;
  }
}
public class AspectWeaver {
 private BeanContainer beanContainer;
    public AspectWeaver(){
        beanContainer = BeanContainer.getInstance();
    }
      public void doAopByAspectJ(){
        //1.获取所有的切面类
        Set<Class<?>> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);
        //非空判断
         if (ValidationUtil.isEmpty(aspectSet)){return;}
         //初始化切面描述类集合
         List<AspectInfo> aspectInfoList = packAspectInfoList(aspectSet);
         //遍历容器里面所有的类
          Set<Class<?>> classes = beanContainer.getClasses();
           //初筛  判断这些切面类的是否是为这个类服务的 留下每个类粗筛后的结果
            List<AspectInfo> roughMatchAspectList =  collectRoughMatchedAspectListForSpecificClass(aspectInfoList,targetClass);
             //对每个类粗筛后的 尝试织入
            wrapIfNecessary(roughMatchAspectList,targetClass);

然后补充上出现的方法。


    /**拼接切面描述类List
     * @param aspectSet
     * @return
     */
    private List<AspectInfo> packAspectInfoList(Set<Class<?>> aspectSet) {
        List<AspectInfo> aspectInfoList = new ArrayList<>();
        for (Class<?> aspectClass : aspectSet) {
            if (verifyAspect(aspectClass)){
                Order orderTag = aspectClass.getAnnotation(Order.class);
                Aspect aspectTag = aspectClass.getAnnotation(Aspect.class);
                DefaultAspect defaultAspect = (DefaultAspect) beanContainer.getBean(aspectClass);
                //初始化表达式定位器
                PointCutLocator pointCutLocator = new PointCutLocator(aspectTag.pointCut());
                AspectInfo aspectInfo = new AspectInfo(orderTag.value(),defaultAspect,pointCutLocator);
                //添加进列表
                aspectInfoList.add(aspectInfo);
            }else {
                throw  new RuntimeException("当前切面类必须持有@Aspect和 @Order 和继承自DefaultAspect,且符合规范");
            }
        }
        return aspectInfoList;
    }
 /**
     * 初筛
     * @param aspectInfoList
     * @param targetClass
     * @return 返回初筛后的列表
     */
    private List<AspectInfo> collectRoughMatchedAspectListForSpecificClass(List<AspectInfo> aspectInfoList, Class<?> targetClass) {
        List<AspectInfo> roughMatchAspectList = new ArrayList<>();
        if (ValidationUtil.isEmpty(aspectInfoList)){return roughMatchAspectList;}
        for (AspectInfo aspectInfo : aspectInfoList) {
            //初筛
            boolean matches = aspectInfo.getPointCutLocator().roughMatches(targetClass);
            //如果匹配 就加入
            if (matches){
                roughMatchAspectList.add(aspectInfo);
            }
        }
        return roughMatchAspectList;
    }
 /**
     * 尝试织入逻辑
     * @param roughMatchAspectList
     * @param targetClass
     */
    private void wrapIfNecessary(List<AspectInfo> roughMatchAspectList, Class<?> targetClass) {
        if (ValidationUtil.isEmpty(roughMatchAspectList)){
            return;
        }
        //创建动态代理对象
        AspectListExecutor executor = new AspectListExecutor(targetClass,roughMatchAspectList);
        Object proxyBean = ProxyCreator.createProxy(targetClass, executor);
        //替换被代理的对象
        beanContainer.addBean(targetClass,proxyBean);
    }

精确筛选的逻辑放在AspectListExecutor里面

/**
 * 网被代理的方法添加横切逻辑
 */
@Data
@NoArgsConstructor
public class AspectListExecutor implements MethodInterceptor {
    //被代理的class
    private Class<?> targetClass;
    //切面信息集合 照顾多个AOP的 情况
    private List<AspectInfo> sortedAspectInfoList;
    public AspectListExecutor(Class<?> targetClass,List<AspectInfo> aspectInfos){
        this.targetClass = targetClass;
        this.sortedAspectInfoList = sort(aspectInfos);
    }

    private List<AspectInfo> sort(List<AspectInfo> aspectInfos) {
        //升序排列
       Collections.sort(aspectInfos, new Comparator<AspectInfo>() {
            @Override
            public int compare(AspectInfo o1, AspectInfo o2) {
                return o1.getOrderIndex() - o2.getOrderIndex();
            }
        });
       return aspectInfos;
    }

    /**
     *
     * @param o 被增强的对象
     * @param method 需要拦截的方法
     * @param args 方法参数
     * @param methodProxy 代理方法
     * @return 返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 2.0 代码 精确筛选
        collectAccurateMatchAspectList(method);
        Object returnValue = null;
        if (ValidationUtil.isEmpty(sortedAspectInfoList)){
            //就算为空也要执行原来的方法啊
            return methodProxy.invokeSuper(o,args);
        }
        //1.按照order的顺序执行完毕所有切面的before方法
        invokeBeforeAdvices(method,args);
        try {
            //2。 执行被代理的方法
            returnValue = methodProxy.invokeSuper(o,args);
            //3. 如果被代理方法正常返回,按照order的顺序 逆序执行afterReturning
            returnValue =  invokeAfterReturningAdvices(method,args,returnValue);
        }catch (Exception e){
            //执行异常时
            invokeAfterThrowingAdvices(method,args,e);
        }
        return returnValue;
    }

    /**
     * 精确匹配 留下符合精确匹配的结果
     * @param method
     */
    private void collectAccurateMatchAspectList(Method method) {
        if(ValidationUtil.isEmpty(sortedAspectInfoList)){return;}
        Iterator<AspectInfo> iterator = sortedAspectInfoList.iterator();
        while (iterator.hasNext()){
            AspectInfo aspectInfo = iterator.next();
            //区别两种方式
            //如果注解不为空 校验注解
            //精确校验
            if (aspectInfo.getPointCutLocator().accurateMatches(method) == false){
                iterator.remove();
            }
        }
    }

    /**
     * 发生异常的时候执行 降序
     * @param method
     * @param args
     * @param e
     */
    private void invokeAfterThrowingAdvices(Method method, Object[] args, Exception e) throws Throwable {
        for (int i = sortedAspectInfoList.size() -1; i >=0 ; i--) {
            sortedAspectInfoList.get(i).getAspectObject()
                    .afterThrowing(targetClass,method,args,e);
        }
    }

    /**
     * 如果代理方法正常返回,降序执行afterAdvice
     * @param method
     * @param args
     * @param returnValue
     * @return
     */
    private Object invokeAfterReturningAdvices(Method method, Object[] args, Object returnValue) throws Throwable {
        Object res = null;
        for (int i = sortedAspectInfoList.size()-1; i >=0 ; i--) {
           res =  sortedAspectInfoList.get(i).getAspectObject().afterReturning(targetClass, method, args, returnValue);
        }
        return res;
    }

    /**
     * 按照oder的 顺序升序执行
     * @param method
     * @param args
     */
    private void invokeBeforeAdvices(Method method, Object[] args) throws Throwable {
        for (AspectInfo info : sortedAspectInfoList) {
            info.getAspectObject().before(targetClass,method,args);
        }
    }
}

改写原来的测试类

package com.fuyouj.aspect.test;

import com.framework.aop.annotation.Aspect;
import com.framework.aop.annotation.Order;
import com.framework.aop.aspect.DefaultAspect;
import com.framework.core.annotation.Controller;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

/**
 * @Desc
 * @Author FuYouJ
 * @date 2020/6/2 0:40
 */
@Aspect(pointCut = "execution(* com.fuyouj.controller..*.*(..))")
@Order(0)
@Slf4j
public class TestAopOne extends DefaultAspect {
    @Override
    public void before(Class<?> targetClass, Method method, Object[] args) throws Throwable {
       log.info("我是切面逻辑before order0,我增强的目标类是{},我增强的目标方法是{},方法参数{}"
        ,targetClass.getSimpleName(),method.getName(),args);
    }

    @Override
    public Object afterReturning(Class<?> targetClass, Method method, Object[] args, Object returnValue) throws Throwable {
        Integer res = (Integer) returnValue;
        log.info("我是切面逻辑after order0,我增强的目标类是{},我增强的目标方法是{},方法参数{}"
                ,targetClass.getSimpleName(),method.getName(),args);
        res++;
        return res;
    }
}
package com.fuyouj.aspect.test;

import com.framework.aop.annotation.Aspect;
import com.framework.aop.annotation.Order;
import com.framework.aop.aspect.DefaultAspect;
import com.framework.core.annotation.Controller;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

/**
 * @Desc
 * @Author FuYouJ
 * @date 2020/6/2 0:40
 */
@Aspect(pointCut = "execution(* com.fuyouj.controller..*.*(..))")
@Order(1)
@Slf4j
public class TestAopTwo extends DefaultAspect {
    @Override
    public void before(Class<?> targetClass, Method method, Object[] args) throws Throwable {
       log.info("我是切面逻辑before order1,我增强的目标类是{},我增强的目标方法是,方法参数{}"
        ,targetClass.getSimpleName(),method.getName(),args);
    }

    @Override
    public Object afterReturning(Class<?> targetClass, Method method, Object[] args, Object returnValue) throws Throwable {
        Integer res = (Integer) returnValue;
        log.info("我是切面逻辑after order1,我增强的目标类是{},我增强的目标方法是,方法参数{}"
                ,targetClass.getSimpleName(),method.getName(),args);
        res++;
        return res;
    }
}

测试用例

public class TestAop {
    @DisplayName("测试第二个版本的AOP")
    @Test
    public void testAopOne(){
        BeanContainer beanContainer = BeanContainer.getInstance();
        //加载了所有类
        beanContainer.loadBeans("com.fuyouj");
        //AOP
        new AspectWeaver().doAopByAspectJ();
        // ioc
        new DependencyInjector().doIoc();
        TestAopController controller = (TestAopController) beanContainer.getBean(TestAopController.class);
        int say = controller.say();
        System.out.println("======================================返回结果======="+say+"======");
    }
}

在这里插入图片描述

再改进

可以将DefaultAspect这个抽象类改造成接口,因为java只能继承一个类,为了减轻实现的压力。使用 Default关键字。代码是一样可以运行的。

package com.framework.aop.aspect;

/**
 * @Desc
 * @Author FuYouJ
 * @date 2020/5/31 21:24
 */

import java.lang.reflect.Method;

/**
 * 定义切面的通用骨架
 * 通过钩子方法实现
 */
public interface  DefaultAspect {
    /**
     * @param targetClass 被代理的目标类型
     * @param method 被代理的方法
     * @param args 方法的参数
     * @throws Throwable
     */
    default void before(Class<?> targetClass, Method method,Object[] args) throws Throwable{

    } ;

    /**
     *
     * @param targetClass 被代理的目标类型
     * @param method 被代理的方法
     * @param args 方法的参数
     * @param returnValue 返回值
     * @return
     * @throws Throwable
     */
   default  Object afterReturning(Class<?> targetClass,Method method
            ,Object[] args,Object returnValue) throws Throwable{
       return  returnValue;
   }

    /**
     *
     * @param targetClass 被代理的目标类型
     * @param method 被代理的方法
     * @param args 方法的参数
     * @param e 异常
     * @throws Throwable
     */
    default void afterThrowing(Class<?> targetClass,
                              Method method,Object[] args,Throwable e) throws Throwable{

    }
}

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章