互联网架构-Spring5.0源码深度解析-024:SpringBean的Aop通知调用链源码分析

1 SpringAop底层调用链源码分析演示

课程内容:
1.SpringAop源码分析之通知调用链关系
2.递归算法与循环算法区别
3.基于递归算法+责任链模式实现SpringAop调用链

2 SpringAop底层源码流程回顾

SpringAop的底层实现原理
设计模式的运用:代理设计模式、底层五个通知形成调用链采用责任链模式
SpringAop源码分析

  1. 配置@EnableAspectJAutoProxy注解开启SpringAop;
  2. @Import(AspectJAutoProxyRegistrar.class)往IOC容器中注入SpringAop切面类;
  3. registerAspectJAnnotationAutoProxyCreatorIfNecessary()注册切面类;
  4. AnnotationAwareAspectJAutoProxyCreator.class注册到IOC容器中,AOP入口;
    SpringBean的生命周期中,后置处理器在bean对象初始化之前和之后实现处理。根据源码分析可知,AbstractAutoProxyCreator 祖宗类有BeanPostProcessor。
  5. beanProcessor.postProcessAfterInitialization(result, beanName);
  6. wrapIfNecessary()判断该对象是否在aop切入点扫包范围内;
  7. createAopProxy()判断该被代理类是否有实现接口,如果有实现接口的话,采用jdk动态代理,否则使用cglib代理;
  8. 使用JDKDynamicAopProxy创建代理类对象;
  9. 当在调用目标方法的时候就会执行到JDKDynamicAopProxy的invoke方法;
  10. 底层使用集合存放五种通知,然后再使用责任链模式循环的调用。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3 循环遍历与递归算法实现的区别

可以使用递归算法代替循环使用

public class Test {

    private static int index; // 记录当前循环调用的位置
    public static void main(String[] args) {
        // 循环目的 遍历数据
        ArrayList<String> strings = new ArrayList<>();
        strings.add("mayikt");
        strings.add("maple");
        strings.add("fire");
//        for (int i = 0; i < strings.size(); i++) {
//            System.out.println(strings.get(i));
//        }
        // 递归算法 循环不停调用自己的方法 自己调用自己 有栈的深度
        recurrence(strings);
    }

    // 自己调用自己 代替循环 场景:查询数据量过大内存溢出
    public static void recurrence(ArrayList<String> strings) {
        if(index == strings.size()){
            // 数据已经获取完毕,退出防止溢出
            return;
        }
        String s = strings.get(index++);
        System.out.println("s:" + s);
        recurrence(strings);
    }
}

4 纯手写SpringAop调用链思路分析

Aop调用链依赖关系:前置通知→环绕通知之前→目标方法→环绕通知之后→后置通知
底层通过递归算法+责任链模式实现
SpringAop使用集合存放五个通知链 有序
[0] 环绕通知之前
[1] 前置通知
[2] 环绕通知之后
[3] 后置通知
执行目标方法→通过递归算法指针指定目标方法的执行

5 纯手写SpringAop调用链代码01

在这里插入图片描述

6 纯手写SpringAop调用链代码02

模拟SpringAop五个通知调用链关系
目标方法

public class UserService {
    public void login(String userName, Integer userAge) {
        System.out.println("userName:" + userName + ",userAge:" + userAge);
    }
}

方法拦截器接口及前置/后置通知实现类

public interface MethodInterceptor {
    /**
     * 定义共同通知骨架
     */
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException;
}
public class BeforeMethodInterceptor implements MethodInterceptor {
    @Override
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        System.out.println(">>前置通知");
        methodInvocation.process();// 递归调用
    }
}
public class AfterMethodInterceptor implements MethodInterceptor {

    @Override
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        methodInvocation.process();
        System.out.println(">>后置通知");
    }
}

方法执行接口及实现类

public interface MethodInvocation {

    public void process() throws InvocationTargetException, IllegalAccessException;
}
public class DefaultMethodInvocation implements MethodInvocation {
    public DefaultMethodInvocation(List<MethodInterceptor> methodInterceptors) {
        this.methodInterceptors = methodInterceptors;
    }

    public DefaultMethodInvocation(List<MethodInterceptor> methodInterceptors, Object target, Method method, Object[] args) {
        this.methodInterceptors = methodInterceptors;
        this.target = target;
        this.method = method;
        this.args = args;
    }

    // 存放所有的通知
    private List<MethodInterceptor> methodInterceptors;
    private Object target;// 目标对象
    private Method method;// 目标方法
    private Object args[];// 目标参数

    private int index; // 记录当前链调用位置

    /**
     * 能够把通知链形成关联
     *
     * @return
     */
    @Override
    public void process() throws InvocationTargetException, IllegalAccessException {
        if (index == methodInterceptors.size()) {
            method.invoke(target, args);// 通过java反射机制执行目标方法
            return;
        }
        MethodInterceptor methodInterceptor = methodInterceptors.get(index++);
        methodInterceptor.invoke(this);
    }
}

测试类

public class Test001 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 1.装配所有的通知存放到集合中
        ArrayList<MethodInterceptor> methodInterceptors = new ArrayList<>();
        methodInterceptors.add(new BeforeMethodInterceptor());
        methodInterceptors.add(new AfterMethodInterceptor());
        // 2.创建目标方法
        UserService userService = new UserService();
        Method loginMethod = UserService.class.getMethod("login", String.class, Integer.class);
        Object[] objects = {"mayikt", 666};
        new DefaultMethodInvocation(methodInterceptors, userService, loginMethod, objects).process();
    }
}

运行结果:
在这里插入图片描述
要点:当执行到后置通知的时候,先回调,回调函数中此时刚好满足指针记录等于列表长度条件,执行目标方法,返回继续执行后置通知。

7 纯手写SpringAop调用链代码03

加上环绕通知

public class AroundMethodInterceptor implements MethodInterceptor {

    @Override
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        System.out.println(">>环绕通知之前");
        methodInvocation.process();
        System.out.println(">>环绕通知之后");
    }
}
public class Test001 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 1.装配所有的通知存放到集合中
        ArrayList<MethodInterceptor> methodInterceptors = new ArrayList<>();
        methodInterceptors.add(new AroundMethodInterceptor());
        methodInterceptors.add(new BeforeMethodInterceptor());
        methodInterceptors.add(new AfterMethodInterceptor());

        // 2.创建目标方法
        UserService userService = new UserService();
        Method loginMethod = UserService.class.getMethod("login", String.class, Integer.class);
        Object[] objects = {"mayikt", 666};
        new DefaultMethodInvocation(methodInterceptors, userService, loginMethod, objects).process();
    }
}

运行结果:
在这里插入图片描述
注意:实际应用中通知执行顺序如下图所示:
在这里插入图片描述
多个切面类同时生效时,哪个Aspect先执行是随机的,如果需要定义顺序,可以使用@Order注解修饰Aspect类。值越小,优先级越高。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值