Spring Aop 底层责任链思路实现

news/2024/11/27 8:55:37/

动手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();}@Overridepublic 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{@Overridepublic 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{@Overridepublic Object execute(Chian chian) throws Throwable {/** 只做逻辑增强* 如果还有继续调用链的下一个通知* */System.out.println("前置通知(责任链)");//调用链通知return   chian.proeccd();}
}

后置增强

public class AfterAdvice extends BaseAdvice{@Overridepublic Object execute(Chian chian) throws Throwable {try {return chian.proeccd();} finally {System.out.println("后置增强");}}
}

异常处理增强

public  class ThrowAdvice extends  BaseAdvice{@Overridepublic 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{@Overridepublic 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();}@Overridepublic 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

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

谢谢观看 请期待下一篇


http://www.ppmy.cn/news/22210.html

相关文章

软件测试面试之道(持续更新)

1. 软件的生命周期&#xff1f; 软件生命周期是软件从提出&#xff0c;实现&#xff0c;使用&#xff0c;到停止使用的过程。是从可行性研究到需求分析、软件设计、编码、测试、软件发布维护的过程。 2. 常见的测试用例设计方法&#xff1f; &#xff08;1&#xff09;等价类…

基于linux5.15.5的IMX 参考手册 --- 5

基于linux5.15.5的IMX 参考手册 — 5 3.7 SDMA (Smart Direct Memory Access)接口 3.7.1概述 Smart Direct Memory Access (SDMA) API驱动程序控制SDMA硬件。它为其他驱动程序提供了一个API&#xff0c;用于在MCU内存空间和外围设备之间传输数据。支持以下特性: •将通道脚本从…

Python解题 - CSDN周赛第25期 - 水池注水

本期四道题都是在每日一练出现过多次的老题&#xff0c;而且后两道题的思维难度颇大&#xff0c;尤其最后一题-水池注水&#xff0c;如果没有提前准备过&#xff0c;问哥是万万不可能在两个小时内做出来的。所以&#xff0c;拿到这个名次&#xff0c;问哥心里其实很虚。提交之后…

DSP_定义一个大的全局数组_探索之路

前言 最近在做基于dsp平台的无通信接口系统辨识&#xff0c;辨识的时候会有很大的数据需要存到一个数组当中&#xff0c;而dsp如果定义一个很大的全局数组&#xff0c;编译会报错。 本文将探索如何解决这个报错以及全局数组的大小极限。 正文 首先&#xff0c;我们定义了一个…

【JVM】Java类加载机制详解

【JVM】Java类加载机制详解 文章目录【JVM】Java类加载机制详解一&#xff1a;类加载子系统1&#xff1a;类加载器子系统的作用2&#xff1a;加载器 ClassLoader 的角色二&#xff1a;类的加载过程1&#xff1a;加载阶段2&#xff1a;验证阶段&#xff1a;确保被加载的类的正确…

Acwing——第 89 场周赛

题目链接 4803. 满足的数 简单 4804. 构造矩阵 中等 4805. 加减乘 困难 题目描述 4803. 满足的数 给定 n个不超过 5 的正整数 a1,a2,…,an。 不妨设 Sa1a2…an。 请你统计&#xff0c;一共有多少个不同的整数 x 能够同时满足以下所有条件&#xff1a; 1≤x≤51≤x≤51≤x≤…

GcExcel-JAVA 6.0.3-Documents for Excel

在更短的时间内生成 Excel 电子表格&#xff0c;不依赖于 Excel&#xff01; 在任何应用程序中转换、计算、格式化和解析电子表格。快速高效&#xff1a;其轻巧的尺寸意味着 Documents for Excel 针对快速处理大型 Excel 文档进行了优化使用适用于 Windows、Linux 和 Mac 的 J…

【数据结构(5)】2.3 线性表的类型定义

文章目录1. 线性表的抽象数据类型定义2. 线性表的基本操作1. 线性表的抽象数据类型定义 数据对象&#xff1a;就是一些元素&#xff0c;元素的个数大于等于 0。数据关系&#xff1a;ai-1 是 ai 的前驱&#xff0c;同时 ai 是 ai-1 的后继&#xff0c;他们都属于集合 D 2. 线性…