从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解

1. 本章需要完成的内容

  1. 完成AspectListExecutor类的编写
  2. 完成AspectWeaver类的编写
  3. 完成PointcutLocator类的编写
  4. 完成ProxyCreator类的编写

2. 完成PointcutLocator类的编写

2.1 需要完成的代码如下:

package com.wuyiccc.helloframework.aop;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.ShadowMatch;

import java.lang.reflect.Method;

/**
 * @author wuyiccc
 * @date 2020/7/14 9:03
 * 岂曰无衣,与子同袍~
 */
public class PointcutLocator {

    /**
     * Pointcut解析器,直接给它赋值上Aspectj的所有表达式,以便支持对众多表达式的解析
     */
    private PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(PointcutParser.getAllSupportedPointcutPrimitives());

    /**
     * 表达式解析器
     */
    private PointcutExpression pointcutExpression;

    public PointcutLocator(String expression) {
        this.pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    /**
     * 判断传入的Class对象是否是Aspect的目标代理类,即匹配Pointcut表达式(初筛)
     *
     * @param targetClass 目标类
     * @return 是否匹配
     */
    public boolean roughMatches(Class targetClass) {
        return pointcutExpression.couldMatchJoinPointsInType(targetClass); // 只能校验within,对于execution,call,get,set等无法校验的表达式,直接返回true
    }

    /**
     * 判断传入的Method对象是否是Aspect的目标代理方法,即匹配Pointcut表达式(精筛)
     * @param method
     * @return
     */
    public boolean accurateMatches(Method method) {
        ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
        if (shadowMatch.alwaysMatches()) {
            return true;
        }
        return false;
    }

}

2.2 PointcutLocator类相关方法讲解:

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第1张图片

3. 完成AspectListExecutor类的编写

3.1 需要完成的代码如下:

package com.wuyiccc.helloframework.aop;

import com.wuyiccc.helloframework.aop.aspect.AspectInfo;
import com.wuyiccc.helloframework.util.ValidationUtil;
import lombok.Getter;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
 * @author wuyiccc
 * @date 2020/7/14 9:03
 * 岂曰无衣,与子同袍~
 */
public class AspectListExecutor implements MethodInterceptor {

    private Class targetClass;

    @Getter
    private List sortedAspectInfoList;


    public AspectListExecutor(Class targetClass, List sortedAspectInfoList) {
        this.targetClass = targetClass;
        this.sortedAspectInfoList = sortAspectInfoList(sortedAspectInfoList);
    }

    /**
     * 按照order的值进行升序排序,确保Order值小的aspect先被织入
     *
     * @param aspectInfoList
     * @return
     */
    private List sortAspectInfoList(List aspectInfoList) {
        // 升序排列
        Collections.sort(aspectInfoList, new Comparator() {
            @Override
            public int compare(AspectInfo o1, AspectInfo o2) {
                return o1.getOrderIndex() - o2.getOrderIndex();
            }
        });
        return aspectInfoList;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        Object returnValue = null;

        collectAccurateMatchedAspectList(method);

        if (ValidationUtil.isEmpty(sortedAspectInfoList)) {
            return methodProxy.invokeSuper(proxy, args);
        }
        // 1. 按照order的顺序升序执行完所有Aspect的before方法
        invokeBeforeAdvices(method, args);
        try {
            // 2. 执行被代理类的方法
            returnValue = methodProxy.invokeSuper(proxy, args);
            // 3. 如果被代理方法正常返回,则按照order的顺序降序执行完所有Aspect的afterReturning方法
            invokeAfterReturningAdvices(method, args, returnValue);

        } catch (Exception e) {
            // 4. 如果被代理方法抛出异常,则按照order的顺序降序执行完所有Aspect的afterThrowing方法
            invokeAfterThrowingAdvices(method, args, e);
        }
        return returnValue;
    }

    private void collectAccurateMatchedAspectList(Method method) {
        if (ValidationUtil.isEmpty(sortedAspectInfoList)) {
            return;
        }
        Iterator it = sortedAspectInfoList.iterator();
        while (it.hasNext()) {
            AspectInfo aspectInfo = it.next();
            if (!aspectInfo.getPointcutLocator().accurateMatches(method)) {
                it.remove(); // 需要用Iterator自带的remove,不能用sortedAspectInfoList的remove,否则就会出现并发修改异常
            }
        }
    }

    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);
        }
    }

    private void invokeAfterReturningAdvices(Method method, Object[] args, Object returnValue) throws Throwable {

        for (int i = sortedAspectInfoList.size() - 1; i >= 0; i--) {
            sortedAspectInfoList.get(i).getAspectObject().afterReturning(targetClass, method, args, returnValue);
        }
    }

    private void invokeBeforeAdvices(Method method, Object[] args) throws Throwable {

        for (AspectInfo aspectInfo : sortedAspectInfoList) {
            aspectInfo.getAspectObject().before(targetClass, method, args);
        }
    }
}

3.2 AspectListExecutor类相关方法讲解:

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第2张图片

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第3张图片

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第4张图片

4. 完成ProxyCreator类的编写

4.1 需要完成的代码及讲解如下:

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第5张图片

5. 完成AspectWeaver类的编写

5.1 需要完成的代码如下:

package org.myframework.aop;

import org.myframework.aop.annotation.Aspect;
import org.myframework.aop.annotation.Order;
import org.myframework.aop.aspect.AspectInfo;
import org.myframework.aop.aspect.DefaultAspect;
import org.myframework.core.BeanContainer;
import org.myframework.util.ValidationUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author wuyiccc
 * @date 2020/6/16 8:49
 * 岂曰无衣,与子同袍~
 */
public class AspectWeaver {

    private BeanContainer beanContainer;

    public AspectWeaver() {
        beanContainer = BeanContainer.getInstance();
    }

    public void doAop() {

        // 1. 获取所有的切面类
        Set> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);
        if (ValidationUtil.isEmpty(aspectSet)) {
            return;
        }
        // 2. 拼装AspectInfoList
        List aspectInfoList = packAspectInfoList(aspectSet);
        // 3. 遍历容器里的类
        Set> classSet = beanContainer.getClasses();
        for (Class targetClass : classSet) {
            // 排除AspectClass自身
            if (targetClass.isAnnotationPresent(Aspect.class)) {
                continue;
            }
            // 4. 粗筛符和条件的Aspect
            List roughMatchedAspectList = collectRoughMatchAspectListForSpecificClass(aspectInfoList, targetClass);
            // 5. 尝试进行Aspect织入
            wrapIfNecessary(roughMatchedAspectList, targetClass);
        }
    }

    private void wrapIfNecessary(List roughMatchedAspectList, Class targetClass) {
        if (ValidationUtil.isEmpty(roughMatchedAspectList)) {
            return;
        }
        // 创建动态代理对象
        AspectListExecutor aspectListExecutor = new AspectListExecutor(targetClass, roughMatchedAspectList);
        Object proxyBean = ProxyCreator.createProxy(targetClass, aspectListExecutor);
        beanContainer.addBean(targetClass, proxyBean);
    }

    private List collectRoughMatchAspectListForSpecificClass(List aspectInfoList, Class targetClass) {
        List roughMatchedAspectList = new ArrayList<>();
        for (AspectInfo aspectInfo : aspectInfoList) {
            // 粗筛
            if (aspectInfo.getPointcutLocator().roughMatches(targetClass)) {
                roughMatchedAspectList.add(aspectInfo);
            }
        }
        return roughMatchedAspectList;
    }

    private List packAspectInfoList(Set> aspectSet) {
        List 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 and @Order must be added to the Aspect class, and Aspect class must extend from DefaultAspect");
            }
        }
        return aspectInfoList;
    }


    // 框架中一定要遵守给Aspect添加的@Aspect和@Order标签的规范,同时,必须继承自DefaultAspect.class
    private boolean verifyAspect(Class aspectClass) {
        return aspectClass.isAnnotationPresent(Aspect.class)
                && aspectClass.isAnnotationPresent(Order.class)
                && DefaultAspect.class.isAssignableFrom(aspectClass);

    }
}

5.2 AspectWeaver类相关方法解析:

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第6张图片

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第7张图片

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---07. AOP功能实现以及讲解_第8张图片

github地址:https://github.com/wuyiccc/he...

你可能感兴趣的:(java,springboot,spring,后端)