menu 冷 の Codeworld
search self_improvement
目录

Spring Aop 底层责任链思路实现

冷环渊
冷环渊 2023年02月05日  ·  阅读 537

动手AOP责任链实现

简单了解 AOP

Spring 的两个重要特性之一 AOP 面向切面编程

image-20230204155405588

它的作用简单来说就是解耦 可以通过代理类的方式实现在不改变类本身的代码的情况下做到功能上的增强 , 了解它能做些什么我们就可以去思考怎么去实现它 , 这里涉及到责任链模式 (后续在细说) 。

想要去实现简单的aop 我们至少要做到 :

  • 拥有目标类
  • 动态代理目标类
  • 自定义通知方法

在实现aop 之前呢 我们需要简单复习一些前置知识 在复习之前 确认使用的依赖和版本 避免demo出现意外的bug

Java版本 : 1.8

Maven 版本 : 3.6.x

==依赖==

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>

动态代理(代理目标类)

了解代理,我们需要复习一下代理的知识。

目前来看 代理分为两种 ,用文字就可以很简单的讲述静态代理和动态代理。

  • 静态代理可以实现代理 但是受限制于抽象类,无法去代理抽象类之外的对象
  • 动态代理依赖反射机制 可以实现对任何类的代理

创建目标类

我们就用Userservice 来作为我们的代理目标类

public class UserService {
    
    public Object insert  ()
    {
        System.out.println("==插入用户成功==");
        return "user insert ok";
    }
    
}

创建代理工厂

这里我们使用cglib 来作为动态代理的方式, 其实通过实现动态代理的支持类我们就可以实现简单的 aop 增强 ,

代码案例

public class ProxyFactory implements MethodInterceptor {
    private Object target;

    public UserService getProxy(Object target){
        //被代理对象
        this.target = target;
        //cglib 生成代理对象
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        //设置类加载器
        enhancer.setClassLoader(target.getClass().getClassLoader());
        //生成代理对象
        return (UserService)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //执行目标方法
        Object result = null;

        try {
            //前置通知
            System.out.println("前置通知");
             result = method.invoke(target, objects);

            //    返回通知
            System.out.println("返回通知");
        } catch (Throwable e) {
            //异常通知
            System.out.println("异常通知");
            throw new RuntimeException(e);
        } finally {
        //    后置通知
            System.out.println("后置通知");
        }

        return result;
    }
}

测试

public class Run {
    public static void main(String[] args) {
        UserService userService = new UserService();
        userService.insert();
        UserService userService1 = new ProxyFactory().getProxy(userService);
        userService1.insert();

    }
}

image-20230204163324899

只要我们在 标有注释的地方添加代码 是不是简单的切面增强就成了 ,这个时候就会有一个需要思考的问题, 想想我们在Spring 中使用的AOP,在标注切面和增强注解的情况下,Spring才帮我们去实现切面增强 。

所以到这里才是刚刚开始 ,我们使用AOP 的本意是什么 解耦 如果想上面案例这样写的话 岂不是掩耳盗铃, 本类解耦了 代理工厂耦合又高了起来 完全没有达到效果 所以接下来 我们要去解决这个问题

  • 提供灵活性
  • 解耦合
  • 是不是可以使用设计模式来解决问题呢

责任链模式

我们希望使用设计模式来增加我们自己demoAOP 的 灵活性,这里简单的介绍一下责任链模式

为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

PS: 递归

image-20230204164417938

那我们实现责任链模式的结构是什么呢?

image-20230204164549365

这里我们实现前置增强来演示 责任链模式的上手思路

责任链

我们用递归的方式来做通知的不断调用

public class Chian {

    //记录index下标
    private int index=  -1;
    private List<BaseAdvice> adviceList;

    public Chian(List<BaseAdvice> adviceList) {
        this.adviceList = adviceList;
    }

    public Object proeccd() throws Throwable{
        if(index == adviceList.size()-1){
            System.out.println("==执行目标方法==");
            return null;
        }
        return  adviceList.get(++index).execute(this);
    }
}

增强通知基类

public abstract class BaseAdvice {

    public abstract Object execute(Chian chian) throws Throwable;

}

前置增强类

public class BeforeAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        /*
        * 只做逻辑增强
        * 如果还有继续调用链的下一个通知
        * */
        System.out.println("前置通知");
        //调用链通知
        return   chian.proeccd();
    }
}

测试

public static void main(String[] args) throws Throwable {
     List<BaseAdvice> adviceList = new ArrayList<>();
    adviceList.add(new BeforeAdvice());
    Chian chian = new Chian(adviceList);
    chian.proeccd();
}

image-20230204170548913

可以看出来结果是与之前的代理方法结果是一致的,通过链式调用+递归来完成目标解耦并且增加灵活性

实现AOP

增强实现

四种增强 这里没有实现环绕增强,因为环绕相当于是其他增强的组合

基类

public abstract class BaseAdvice {

    public abstract Object execute(Chian chian) throws Throwable;

}

四种增强类

前置增强

public class BeforeAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        /*
        * 只做逻辑增强
        * 如果还有继续调用链的下一个通知
        * */
        System.out.println("前置通知(责任链)");
        //调用链通知
        return   chian.proeccd();
    }
}

后置增强

public class AfterAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {

        try {
            return chian.proeccd();
        } finally {
            System.out.println("后置增强");
        }
    }
}

异常处理增强

public  class ThrowAdvice extends  BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        try {
            return chian.proeccd();
        } catch (Throwable e) {
            System.out.println("异常通知");
            throw new RuntimeException(e);
        }

    }
}

返回处理增强通知

public class ReturnAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        //如果没有异常就走返回通知
        Object value = chian.proeccd();
        System.out.println("返回通知");
            return value;
    }
}

责任链实现

用链表+递归实现责任链,用链表数据结构的特点 来节点调节点执行增强

public class Chian {

    //记录index下标
    private int index=  -1;
    private List<BaseAdvice> adviceList;

    //目标方法
    private Method method;

    //方法参数
    private  Object[] args;
    //目标对象
    private  Object target;

    public Chian(List<BaseAdvice> adviceList) {
        this.adviceList = adviceList;
    }

    public Chian(List<BaseAdvice> adviceList, Method method, Object[] args, Object target) {
        this.adviceList = adviceList;
        this.method = method;
        this.args = args;
        this.target = target;
    }

    public Object proeccd() throws Throwable{
        if(index == adviceList.size()-1){
            return method.invoke(args,target);
        }
        return  adviceList.get(++index).execute(this);
    }
}

代理类实现

public class ProxyFactoryAddChian implements MethodInterceptor {
    private Object target;
    private List<BaseAdvice> adviceList;

    public ProxyFactoryAddChian() {
        adviceList = new ArrayList<>();
        adviceList.add(new BeforeAdvice());
        adviceList.add(new ReturnAdvice());
        adviceList.add(new AfterAdvice());
        adviceList.add(new ThrowAdvice());
    }

    public UserService getProxy(Object target){
        //被代理对象
        this.target = target;
        //cglib 生成代理对象
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        //设置类加载器
        enhancer.setClassLoader(target.getClass().getClassLoader());
        //生成代理对象
        return (UserService)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //在生产代理的时候就把链设置好
        Chian chian = new Chian(adviceList,method,objects,target);
        return chian.proeccd();
    }
}

测试

public class Run {
    public static void main(String[] args) throws Throwable {
        UserService userService = new UserService();
        //userService.insert();
        UserService userService1 = new ProxyFactoryAddChian().getProxy(userService);
        userService1.insert("编程导航小冷Demo");
    }
}

image-20230204195338199

总结

实现增强功能其实我们就是将输出语句的位置都换成想要实现的代码就可以了,可能看起来有些疑问 ,这和spring的AOP并不是完全像,那是因为 AOP 有部分是有ioc的参与的 但是很巧,我们之前实现过ioc

如果这个系列更新的还好的话 之后可以尝试做个小型的Spring。 和小冷一起读spring源码在去根据自己想想怎么用自己的思路去实现。

那么这次的责任链动手实践 我们都学到了什么呢 ?

  • 责任链模式的应用
  • 递归的运用
  • 学习到类优秀框架源码的思路
  • 获得一个半成品的aopdemo

希望大伙可以继续观看小冷的技术文章 一起进步 你们的观看可以给予小冷莫大的鼓励

谢谢观看 请期待下一篇

分类: