细说之前博客--手写简单AOP

是什么时AOP

aop在我的理解的就是干动态代理,方法增加的。专业一点就是面向切面编程!!
我们实现aop选择spring实现aspectJ aop框架,说白了就是那几个注解:pointCut,before,after,afterthrowing,ascept
不过实现之前还是先了解一下aop的相关概论:

  • pointCut:切入点,可以理解要增强的具体方法
  • advice:通知 ,就是要增加的具体逻辑,比如前置通知before注解啊,就是在切入点执行之前执行你要执行的逻辑就行了
  • aspect: 切面,嗯,,这个我也不是很懂,大概就是切入点和avice通知和在一起,这个类叫切面吧,代码是这样表现的。

实现aop的具体思路

  1. 之前ioc文章里讲过,我们先后初始化BeanDefinition对象,在BeanDefinition对象里面定义一个属性判断是否是切面
  2. 初始化aop,遍历BeanDefinition,如果是,则将pointcut,before等注解解析成GPAopConfig对象
  3. 然后在getBean方法里面,class.newInstance();之后判断是否需要动态代理,就是class是否有切入点
  4. 如果有就利用动态代理(jdk,cglib)返回一个代理后的对象,后面的属性赋值什么的都对代理对象进行

相关类及其作用

  • GPAopConfig:相当于一个切面,储蓄切面的信息
    GPAopConfig
    这个我要说一下,我能力不够,无法解析pointCui对应的表达式,于是想出了给pointCut注解3个属性,分别是package,class,methon,这样我就可以定位到是否要被代理

  • GPAdvice:通知对象,里面有切面和要加强的方法
    GPAdvice

  • GPAdviceSupport: 这个是个很重要的类,里面有methodCache对象(存放所有被增强方法及相对应的通知和切面(GPAdvice对象))

在这里插入图片描述
这个map的key是要被加强的方法,value是个map1,map1就是前置后置啊啥的,map1的key是before,after这种,value就是具体的通知,还是个list,通知有个order是排序用的。

具体思路代码

  1. 初始化:
/**
     * 初始化aop容器
     */
    public void initAspect() {
        ConcurrentHashMap<String, BeanDefinition> beanDefinitions = BeanFactory.getBeanDefinitions();

        List<GPAopConfig> configs = new ArrayList<>();
        beanDefinitions.forEach((beanName, beanDefinition) -> {
            if (beanDefinition.isAspect()) {
                Class clazz = beanDefinition.getClazz();
                GPAopConfig aopConfig = new GPAopConfig();
                if (clazz.isAnnotationPresent(Order.class)) {
                    aopConfig.setOrder(((Order) clazz.getDeclaredAnnotation(Order.class)).value());
                } else {
                    aopConfig.setOrder(1);
                }
                Method[] declaredMethods = clazz.getDeclaredMethods();
                for (Method declaredMethod : declaredMethods) {

                    String methodString = declaredMethod.getName();
                    if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
                            "hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
                            "notifyAll".equals(methodString)) {
                        continue;
                    }
                    aopConfig.setAspectClass(clazz.getName());
                    try {
                        if (declaredMethod.isAnnotationPresent(PointCut.class)) {
                            PointCut annotation = declaredMethod.getAnnotation(PointCut.class);
                            aopConfig.setPointCut_class(annotation.class_name());
                            aopConfig.setPointCut_package(annotation.package_name());
                            aopConfig.setPointCut_method(annotation.method_name());
                        }
                        if (declaredMethod.isAnnotationPresent(Before.class)) {
                            aopConfig.setAspectBefore(declaredMethod.getName());
                        }
                        if (declaredMethod.isAnnotationPresent(After.class)) {
                            aopConfig.setAspectAfter(declaredMethod.getName());
                        }
                        if (declaredMethod.isAnnotationPresent(AfterThrowing.class)) {
                            aopConfig.setAfterThrowing(declaredMethod.getName());
                        }
                        if (declaredMethod.isAnnotationPresent(AfterReturning.class)) {
                            aopConfig.setAfterReturning(declaredMethod.getName());
                        }
                        if (declaredMethod.isAnnotationPresent(Around.class)) {
                            aopConfig.setAround(declaredMethod.getName());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
                configs.add(aopConfig);
            }
        });
        AopFactory.setConfigs(configs);

    }
  1. 判断是否需要初始化,如果需要的话将要被加强的mehon放methodCache中
    判断是否需要代理:
GPAdviceSupport config = new GPAdviceSupport();
        config.setTargetClass(clazz);
        config.setTarget(newInstance);
        if (config.pointCutMatch()) {
            try {
                newInstance = new CglibDynamicAopProxy(config).getProxy();
            } catch (Exception e) {
                newInstance = new GPJDKDynamicAopProxy(config).getProxy();
            }

        }
        Object finalNewInstance1 = newInstance;
       

这里是逻辑:,,我把整个类都贴出来吧,不太好说,,

package it.yuzuojian.com.aop;


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GPAdviceSupport {
    private Class targetClass;
    private Object target;
    private Map<Method, Map<String, List<GPAdvice>>> methodCache = new HashMap<>();
    private boolean check = false;


    public boolean pointCutMatch() {

        return check;
    }

    public void parse() {
        List<GPAopConfig> configs = AopFactory.getConfigs();
        configs.forEach((config) -> {
            String pointCut_package = config.getPointCut_package();
            if (targetClass.getPackage().getName().contains(pointCut_package)) {
                String[] pointCut_class = config.getPointCut_class();
                String[] pointCut_method = config.getPointCut_method();
                Map<String, Method> aspectMethods = new HashMap<>();
                Class aspectClass = null;
                try {
                    aspectClass = Class.forName(config.getAspectClass());
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                for (Method declaredMethod : aspectClass.getDeclaredMethods()) {
                    aspectMethods.put(declaredMethod.getName(), declaredMethod);
                }
                if (pointCut_class[0].equals("") && pointCut_method[0].equals("")) {
                    if (!check) {
                        check = true;
                    }
                    init(config, aspectClass, aspectMethods);
                } else if (!pointCut_class[0].equals("") && pointCut_method[0].equals("")) {
                    if (targetClass.getSimpleName().equals(pointCut_class)) {
                        if (!check) {
                            check = true;
                        }
                        init(config, aspectClass, aspectMethods);
                    }
                } else if (pointCut_class[0].equals("") && !pointCut_method[0].equals("")) {
                    init(config, aspectClass, aspectMethods, pointCut_method);

                } else {
                    if (!check) {
                        check = true;
                    }
                    init(config, aspectClass, aspectMethods, pointCut_class, pointCut_method);
                }
            }
        });


    }

    public void init(GPAopConfig config, Class aspectClass, Map<String, Method> aspectMethods) {
        for (Method declaredMethod : this.targetClass.getDeclaredMethods()) {
            String methodString = declaredMethod.getName();
            if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
                    "hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
                    "notifyAll".equals(methodString)) {
                continue;
            }
            Map<String, List<GPAdvice>> advices = methodCache.get(declaredMethod);
            if (advices == null || advices.size() == 0) {
                advices = new HashMap<>();
            }
            try {
                if (!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
                    List<GPAdvice> before = advices.get("before");
                    if (before == null || before.size() == 0) {
                        before = new ArrayList<>();
                    }
                    before.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectBefore()), config.getOrder()));
                    advices.put("before", before);
                }
                if (!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
                    List<GPAdvice> after = advices.get("after");
                    if (after == null || after.size() == 0) {
                        after = new ArrayList<>();
                    }
                    after.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectAfter()), config.getOrder()));
                    advices.put("after", after);
                }
                if (!(null == config.getAfterThrowing() || "".equals(config.getAfterThrowing()))) {
                    List<GPAdvice> afterThrowing = advices.get("afterThrowing");
                    if (afterThrowing == null || afterThrowing.size() == 0) {
                        afterThrowing = new ArrayList<>();
                    }
                    GPAdvice gpAdvice = new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAfterThrowing()), config.getOrder());
                    afterThrowing.add(gpAdvice);
                    advices.put("afterThrowing", afterThrowing);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            methodCache.put(declaredMethod, advices);

        }
    }

    public void init(GPAopConfig config, Class aspectClass, Map<String, Method> aspectMethods, String[] pointCut_method) {
        for (Method declaredMethod : this.targetClass.getDeclaredMethods()) {
            String methodString = declaredMethod.getName();
            if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
                    "hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
                    "notifyAll".equals(methodString)) {
                continue;
            }
            if (methodString.contains("throws")) {
                methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim();
            }
            if (check(pointCut_method,methodString)) {
                if (!check) {
                    check = true;
                }
                Map<String, List<GPAdvice>> advices = methodCache.get(declaredMethod);
                if (advices == null || advices.size() == 0) {
                    advices = new HashMap<>();
                }
                try {
                    if (!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
                        List<GPAdvice> before = advices.get("before");
                        if (before == null || before.size() == 0) {
                            before = new ArrayList<>();
                        }
                        before.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectBefore()), config.getOrder()));
                        advices.put("before", before);
                    }
                    if (!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
                        List<GPAdvice> after = advices.get("after");
                        if (after == null || after.size() == 0) {
                            after = new ArrayList<>();
                        }
                        after.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectAfter()), config.getOrder()));
                        advices.put("after", after);
                    }
                    if (!(null == config.getAfterThrowing() || "".equals(config.getAfterThrowing()))) {
                        List<GPAdvice> afterThrowing = advices.get("afterThrowing");
                        if (afterThrowing == null || afterThrowing.size() == 0) {
                            afterThrowing = new ArrayList<>();
                        }
                        GPAdvice gpAdvice = new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAfterThrowing()), config.getOrder());
                        afterThrowing.add(gpAdvice);
                        advices.put("afterThrowing", afterThrowing);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                methodCache.put(declaredMethod, advices);
            }

        }
    }
    public boolean check(String[] arr,String name){
        for (String s : arr) {
            if(s.equals(name)){
                return true;
            }
        }

        return false;
    }


    public void init(GPAopConfig config, Class aspectClass, Map<String, Method> aspectMethods, String pointCut_class[], String pointCut_method[]) {
        if (check(pointCut_class, targetClass.getSimpleName())) {
            for (Method declaredMethod : this.targetClass.getDeclaredMethods()) {
                String methodString = declaredMethod.getName();
                if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
                        "hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
                        "notifyAll".equals(methodString)) {
                    continue;
                }
                if (methodString.contains("throws")) {
                    methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim();
                }
                if (check(pointCut_method, methodString)) {
                    if (!check) {
                        check = true;
                    }
                    Map<String, List<GPAdvice>> advices = methodCache.get(declaredMethod);
                    if (advices == null || advices.size() == 0) {
                        advices = new HashMap<>();
                    }
                    try {
                        if (!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
                            List<GPAdvice> before = advices.get("before");
                            if (before == null || before.size() == 0) {
                                before = new ArrayList<>();
                            }
                            before.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectBefore()), config.getOrder()));
                            advices.put("before", before);
                        }
                        if (!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
                            List<GPAdvice> after = advices.get("after");
                            if (after == null || after.size() == 0) {
                                after = new ArrayList<>();
                            }
                            after.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectAfter()), config.getOrder()));
                            advices.put("after", after);
                        }
                        if (!(null == config.getAfterThrowing() || "".equals(config.getAfterThrowing()))) {
                            List<GPAdvice> afterThrowing = advices.get("afterThrowing");
                            if (afterThrowing == null || afterThrowing.size() == 0) {
                                afterThrowing = new ArrayList<>();
                            }
                            GPAdvice gpAdvice = new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAfterThrowing()), config.getOrder());
                            afterThrowing.add(gpAdvice);
                            advices.put("afterThrowing", afterThrowing);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    methodCache.put(declaredMethod, advices);
                }

            }
        }

    }

    public Map<String, List<GPAdvice>> getAdvices(Method method, Class targetClass) throws NoSuchMethodException {
        Map<String, List<GPAdvice>> adviceMap = methodCache.get(method);
        if (null == adviceMap) {
            Method declaredMethod = targetClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
            adviceMap = methodCache.get(declaredMethod);
            this.methodCache.put(declaredMethod, adviceMap);
        }
        return adviceMap;
    }

    public Class getTargetClass() {
        return targetClass;
    }

    public void setTargetClass(Class targetClass) {
        this.targetClass = targetClass;
        parse();
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }


}

  1. 最后就是动态代理了,这个没啥好说的,前面都把对象放入methonCache中了,获取在进行代理就好了,有个排序要注意一下,更具order排序嘛,before跟after要是反的哦,因为是链式的嘛
 public static Object getProxy(GPAdviceSupport config, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Map<String, List<GPAdvice>> adviceMap=config.getAdvices(method,config.getTargetClass());
        Object result=null;
        try {

            List<GPAdvice> befores = adviceMap.get("before");
            befores.sort(new Comparator<GPAdvice>() {
                @Override
                public int compare(GPAdvice o1, GPAdvice o2) {
                    return o1.getOrder()- o2.getOrder();
                }
            });
            for (GPAdvice before : befores) {
                before.getAdviceMethod().invoke(before.getAspect());
            }
            result=method.invoke(config.getTarget(),args);
            List<GPAdvice> afters = adviceMap.get("after");
            afters.sort(new Comparator<GPAdvice>() {
                @Override
                public int compare(GPAdvice o1, GPAdvice o2) {
                    return o2.getOrder()- o1.getOrder();
                }
            });
            for (GPAdvice after : afters) {
                after.getAdviceMethod().invoke(after.getAspect());
            }
        } catch (Exception e) {
            e.printStackTrace();
            List<GPAdvice> afterThrowings = adviceMap.get("afterThrowing");
            afterThrowings.sort(new Comparator<GPAdvice>() {
                @Override
                public int compare(GPAdvice o1, GPAdvice o2) {
                    return o2.getOrder()- o1.getOrder();
                }
            });
            for (GPAdvice afterThrowing : afterThrowings) {
                afterThrowing.getAdviceMethod().invoke(afterThrowing.getAspect());
            }
        }
        return result;
    }

相关事项

我这里实现的也有很多的不足:

  1. pointCut不会解析表示式,用了3个属性去代替
  2. 没有用实现around注解
  3. 比较重要的一点就是我这实现逻辑是一个切面定义一个切入点,这个切面的所有的通知都是只针对这个一个切入点说的,没有实现跟spring一样,一个切面可以有很多个pointCut,方法上可以同时加上pointcut注解和before注解这样,不过想想也不是很难呀,是不是可以针对befor,after这种加上几个map,然后被代理的方法去跟这些map匹配,有兴趣的可以去试一下。

本人目前刚刚毕业,写的不好,逻辑不对或表达不够清楚的可以一起说说,不要喷我就好了,,,源码地址在之前的博客有写!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值