Aop切面编程

学习视频

一、定义模型:订单保存模型,订单更新模型,业务层,日志模型

订单保存模型

/*** @author durunwu* @date 2024-08-20-21:04*/
@Data
public class SaveOrder {private Long id;
}

订单更新模型

/*** @author durunwu* @date 2024-08-20-21:05*/
@Data
public class UpdateOrder {private Long orderId;
}

Service业务层实现保存、更新等操作

/*** @author durunwu* @date 2024-08-20-21:03*/
@Service
public class OrderService {/*** 单纯加注解是没用的,需要定义切面*/@RecordOperate(desc = "保存订单",convert = SaveOrderConvert.class)public Boolean saveOrder(SaveOrder saveOrder){System.out.println("save order, orderId: " + saveOrder.getId());return true;}@RecordOperate(desc = "更新订单", convert = UpdateOrderConvert.class)public Boolean updateOrder(UpdateOrder updateOrder){System.out.println("update order, orderId: " + updateOrder.getOrderId());return true;}}

定义日志模型用来记录订单保存、更新信息

/*** @author durunwu* @date 2024-08-20-21:14*/
@Data
public class OperateLogDO {private Long orderId;private String desc;private String result;}

二、需求

在每次订单操作时,需要记录订单的日志信息,记录日志的操作都是一样的,我们可以提取出来作为公共方法提供使用
但是提取出来之后,怎样去记录不同订单类型的日志呢?
首先每个对象的类型不同、属性不同,难道需要通过判断入参的类型这样去实现吗?不够优雅
解决办法,使用aop切面

/*** @author durunwu* @date 2024-08-20-21:09*/
@SpringBootApplication
public class Application implements CommandLineRunner {@AutowiredOrderService orderService;public static void main(String[] args) {new SpringApplication(Application.class).run(args);}@Overridepublic void run(String... args) throws Exception {/*** 需求:* 需要在每次订单操作时,记录订单的日志信息* 记录日志这个操作都是一样的,需要提取出来单独处理* 但是提出出来之后,怎样去记录不同订单类型的日志呢?难道需要通过判断入参的类型进行校验然后转型吗* 解决办法,使用aop切面*///保存订单,id=1SaveOrder saveOrder = new SaveOrder();saveOrder.setId(1L);orderService.saveOrder(saveOrder);//更新订单 id=2UpdateOrder updateOrder = new UpdateOrder();updateOrder.setOrderId(2L);orderService.updateOrder(updateOrder);}
}

三、Aop实现策略

具体代理实现流程

  1. 定义切入点
  2. 横切逻辑
  3. 植入
    在业务层执行不同的业务操作时,通过环绕切面在方法执行之前和之后做操作,通过切入点ProceedingJoinPoint在方法执行之前通过反射获取到对应的方法签名MethodSignature,通过方法签名获取到当前注解@annotation,然后获取当前注解手动定义的类型Class,使用当前Class类型在Lambda泛化接口Convert< PARAM > 获取到对应日志模型实例,最后通过不同的业务模型去做具体的业务
    注意不推荐使用该操作,如果主业务发生了异常,切面逻辑是不能回滚的

1.Lambda泛化接口

抽象父接口

/*** @author durunwu* @date 2024-08-20-22:32*/
public interface Convert<PARAM> {/*** 通过不同的入参,转换成标准的日志模型*/OperateLogDO convertDurunwu(PARAM param);
}

子实现1:实现订单保存的日志模型

/*** @author durunwu* @date 2024-08-20-22:34*/
public class SaveOrderConvert implements Convert<SaveOrder>{@Overridepublic OperateLogDO convertDurunwu(SaveOrder saveOrder) {OperateLogDO operateLogDO = new OperateLogDO();operateLogDO.setOrderId(saveOrder.getId());return operateLogDO;}
}

子实现2:实现订单更新的日志模型

/*** @author durunwu* @date 2024-08-20-22:35*/
public class UpdateOrderConvert implements Convert<UpdateOrder>{@Overridepublic OperateLogDO convertDurunwu(UpdateOrder updateOrder) {OperateLogDO operateLogDO = new OperateLogDO();operateLogDO.setOrderId(updateOrder.getOrderId());return operateLogDO;}
}

2.定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface RecordOperate {//定义每次操作的类型,默认不填String desc() default "";//定义一个类型,需要是Convert的子类Class<? extends Convert> convert();
}

3.切面逻辑

package com.durunwu.study.demos.oAuth2.daily.aop;import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;/*** 定义切面* @author durunwu* @date 2024-08-20-21:18*/
@Aspect
@Component
public class OperateAspect {/*** 不推荐,主业务发生了异常,切面逻辑不能回滚** 1.定义切入点,把注解RecordOperate的Class Path复制* 2.横切逻辑* 3.值入*///定义切面方法@Pointcut("@annotation(com.durunwu.study.demos.oAuth2.daily.aop.RecordOperate)")public void pointcut() {};//定义线程池private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));//使用环绕通知,定义横向逻辑@Around(value = "pointcut()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {//切入点ProceedingJoinPoint//拿到切入点的返回结果,这里如果抛异常则不记录流水,如果存在异常则抛出Object result = proceedingJoinPoint.proceed();//异步执行threadPoolExecutor.execute(new Runnable() {@Overridepublic void run() {try {//通过反射拿到方法签名Signature signature = proceedingJoinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;//再通过方法签名拿到注解Method method = methodSignature.getMethod();//传入当前注解RecordOperateRecordOperate annotation = method.getAnnotation(RecordOperate.class);//使用注解的convert方法获取传入的类型Class<? extends Convert> convert = annotation.convert();//因为convert是一个类,需要实例化对象,获取对应的实现Convert logConvert = convert.newInstance();OperateLogDO operateLogDO = logConvert.convertDurunwu(proceedingJoinPoint.getArgs()[0]);//构造写入流水的模型,//OperateLogDO operateLogDO = new OperateLogDO();//operateLogDO.setOrderId();//获取注解上定义的操作类型operateLogDO.setDesc(annotation.desc());operateLogDO.setResult(result.toString());//怎么才能获取对应类型的业务id呢? 难道需要if判断是什么类型的对象再去取对应的id?这样不太优雅//解决思路:定义Lambda接口,通过不同的类型去转换,通过不同的入参去拿到一个不同的标准模型//定义Convert接口,入参泛化Convert<PARAM>System.out.println("isnert operateLog" + operateLogDO);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}});return result;}}

四、Debug测试

在这里插入图片描述在这里插入图片描述
控制台输出同步操作和异步操作
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/405253.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Veritas NBU8.3.0.2 安装Master Server及汉化包(篇二)

一、环境自检阶段 1、Master角色地址为192.168.189.2&#xff0c;计算机名称为bakmaster&#xff0c;域名为sszz.com 2、防火墙均已关闭 二、安装Master Server 1、右击“Browser”以管理员身份运行 2、单击“NetBackup Server Software Installation” 3、忽略UAC告警&#…

iOS18升级出现白苹果、无法重启等问题,要怎么解决

随着苹果iOS 18系统beta版本的推出&#xff0c;不少用户在私信说升级后遇到了白苹果和无法重启等问题。这些问题不仅影响了大家的正常使用&#xff0c;还会导致数据丢失和系统崩溃。本文将详细介绍iOS 18升级后出现白苹果、无法重启等问题的原因及解决方法&#xff0c;帮助大家…

Mysql的相关编程基础知识

一. 配置MySQL 首先下载mysql-5.0.96-winx64&#xff0c;安装过程如下图所示。 1.安装MySQL 5.0 ​ ​ 2.选择手动配置、服务类型、通用多功能型和安装路径 ​ 3.设置数据库访问量连接数为15、端口为3306&#xff08;代码中设置URL用到&#xff09;、编码方式为utf-8 ​ 4.设…

Opencv-C++笔记 (20) : 距离变换与分水岭的图像分割

文章目录 一、图片分割分水岭算法理解分水岭算法过程 二、距离变换与分水岭距离变换常见算法有两种分水岭变换常见的算法步骤 主要函数c代码四、结果展示 一、图片分割 图像分割(Image Segmentation)是图像处理最重要的处理手段之一 图像分割的目标是将图像中像素根据一定的规则…

python之matplotlib (6 等高线和热力图)

等高线 import numpy as np import matplotlib.pyplot as pltdef f(x,y):return (1-x/2x**5y**3)*np.exp(-x**2-y**2) n256 xnp.linspace(-3,3,n) yx X,Ynp.meshgrid(x,y) plt.contourf(X,Y,f(X,Y),8,alpha0.75,cmapviridis) plt.colorbar() Cplt.contour(X,Y,f(X,Y),8,colors…

【Python机器学习系列】建立XGBoost模型预测小麦品种(案例+源码)

这是我的第344篇原创文章。 一、引言 对于表格数据&#xff0c;一套完整的机器学习建模流程如下&#xff1a; 针对不同的数据集&#xff0c;有些步骤不适用&#xff0c;其中橘红色框为必要步骤&#xff0c;欢迎大家关注翻看我之前的一些相关文章。前面我介绍了机器学习模型的二…

EmguCV学习笔记 VB.Net 4.5 像素距离和连通区域

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 教程VB.net版本请访问&#xff1a;EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问&#xff1a;EmguCV学习笔记 C# 目录-CSD…

什么是黄金期权?黄金期权合约详解

想要了解什么是黄金期权首先要了解一下黄金期货。黄金期货是以现货黄金为标的物的期货品种&#xff0c;其交易代码通常为Au。而黄金期权&#xff0c;又称为黄金期货期权&#xff0c;是一种期权合约&#xff0c;其标的物是黄金期货合约本身&#xff0c;而非黄金现货。这意味着期…

设计模式22-迭代器模式

设计模式22-迭代器模式 迭代器模式&#xff08;Iterator Pattern&#xff09;动机定义结构定义结构结构图解释注意事项 C代码推导多态属性&#xff08;虚函数&#xff09;实现迭代器1. **返回值问题**2. **对象切割问题**3. **内存管理问题**4. **迭代器生命周期问题**5. **接口…

【保姆级教程】5分钟上手 Coze 自建插件,把 AI 接入个人微信

上篇&#xff0c;给大家介绍了一款搭建微信机器人的开源项目&#xff1a; 搭建微信机器人的第4种方式&#xff0c;我造了一个摸鱼小助手 不同于需要付费的项目&#xff0c;它的定制化程度非常高~ 问题来了&#xff1a;怎么接入 AI 能力呢&#xff1f; 考虑到大家对 Coze 智能…

(第三期)书生大模型实战营——OpenXLab部署InternLM2实践——上传模型

OpenXLab 部署 InternLM2 实践指南 上传模型 初始化git设置 # install git sudo apt-get update sudo apt-get install git# install git lfs sudo apt-get update sudo apt-get install git-lfs# use git install lfs git lfs installOpenXLab 使用你在平台的用户名作为 Git…

如何使用midjourney?MidJourney订阅计划及国内订阅教程

国内如何订阅MidJourney 第三方代理 参考&#xff1a; zhangfeidezhu.com/?p474 使用信用卡订阅教程 办理国外信用卡&#xff1a; 这个各自找国外的银行办理就好了。 登录MidJourney&#xff1a; 登录MidJourney网站&#xff0c;进入订阅中心。如果是在Discord频道&#x…

MySQL 高阶三 (索引性能分析)

执行过程 Explain explain select * from student s, course c , student_coure sc where s.id sc.studentid and c.id sc.courseid;EXPLAIN执行计划各字段含义: 【ld】 id相同&#xff0c;执行顺序从上到下; id不同&#xff0c;值越大&#xff0c;越先执行)。 【select_type…

C语言程序设计(初识C语言后部分)

1024M1GB&#xff0c;1GB1级棒。关爱一级棒的程序员们&#xff0c;宠TA没商量&#xff01; 5&#xff09;函数的嵌套调用和链式访问 函数和函数之间可以根据实际的需求进行组合的&#xff0c;也就是相互调用的。 1.嵌套调用 函数可以嵌套调用&#xff0c;但不可以嵌套定义&a…

作业帮 TiDB 7.5.x 使用经验

作者&#xff1a; 是我的海 原文来源&#xff1a; https://tidb.net/blog/5f9784d3 近期在使用 TiDB 时遇到的一些小问题的梳理总结&#xff0c;大部分版本都在6.5.6和7.5.2 1、limit 导致的扫描量过大的优化 研发定时任务每天需要扫描大量数据&#xff0c;到时机器网卡被…

TCP并发服务器模型

1.阻塞IO CPU占用率低,等待资源时将任务挂起,不占用CPU资源,等到拿到资源后继续向下执行 向管道中写入数据 write.c #include "../head.h" int main() {int fd;mkfifo("/tmp/myfifo",0777);char tmpbuff[100]{0};fdopen("/tmp/myfifo",O_WRON…

三十八、【人工智能】【机器学习】【监督贝叶斯网络(Bayesian Networks)学习】- 算法模型

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

39_WAF的概念、功能,ModSecurity部署配置、LAMP环境部署、Ubuntu搭建DVWA靶机测试、测试WAF防御、OWASP规则集的部署

一、WAF的概念 WAF&#xff08; Web Application Firewall &#xff09;&#xff0c;即Web应用防火墙 通过执行一系列HTTP/HTTPS&#xff08;应用层的协议&#xff09;的安全策略为Web应用提供保护的一种网络安全产品。增加攻击者的难度和成本&#xff0c;但不是100%安全。工…

halcon的HObject被释放

经过简述 某项目由我统一管理HObject(区域和图像)的释放。发现某区域被系统外部所释放。可能有两种情况&#xff1a;a&#xff0c;区域交给我后&#xff0c;释放了。b&#xff0c;获取我的区域后释放了。 最终证明是第二种情况&#xff0c;证明如下&#xff1a; a&#xff0c;…

Python数据分析:Pandas与NumPy结合,实现高效数值计算,提升数据分析效率的最佳实践

目前小编的借调任务已经完成&#xff0c;借调到其他组完成了自己的工作&#xff0c;有需要的同学可以看下相关的文章&#xff1a;Python&#xff08;Flask&#xff09; React && Golang&#xff08;Gin&#xff09; Vue(Element)&#xff0c;然后小编认为可以回到原来的…