Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian

简介: Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian

title: Spring Aop 底层责任链思路实现
date: 2023-02-05 18:13:35.713
updated: 2023-02-05 18:13:35.713
url: /archives/springaopdi-ceng-ze-ren-lian-si-lu-shi-xian
categories:
tags: Java | Spring源码

动手AOP责任链实现

简单了解 AOP

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

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

想要去实现简单的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();
    }
}

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

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

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

责任链模式

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

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

PS: 递归

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

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

责任链

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

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

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

实现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");
    }
}

总结

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

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

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

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

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

谢谢观看 请期待下一篇

目录
相关文章
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
8天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
28天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
35 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
13天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
27 1
|
9天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
22 0
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
65 2
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
126 9
|
1月前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
45 0
|
2月前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理