Spring AOP<一>简介与基础使用

spring AOP

img

基础定义

含义使用
切面组织多个Advice,Advice放在切面中定义。也就是说是定义通知的自定义类。自定义的AOP类@Aspect
连接点方法调用,异常抛出可以增强的点JoinPoint :也就是**被增强的方法的总称,可以获取具体方法的信息,然后执行他。一般和环绕通知一起使用**
通知/增强处理(Advice)around, befor, afterafter returing ,after throwing对其进行增强@Around(),获取连接点,然后前后执行增强代码
切入点被增强的方法,规定什么条件下可以增强@anotation():在有这个注解条件下增强execution():执行哪个接口方法,哪个包下方法的时候进行切入
目标
代理
织入增强代码和目标代码通过代理的方式加入到代理类中

举例-Redis分布式锁

这里实现一个基于注解的AOP实现

  • 首先定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RedisLock {/*** 业务键** @return*/String key();/*** 锁的过期秒数,默认是5秒** @return*/int expire() default 5;/*** 尝试加锁,最多等待时间** @return*/long waitTime() default Long.MIN_VALUE;/*** 锁的超时时间单位** @return*/TimeUnit timeUnit() default TimeUnit.SECONDS;
}作者:pjmike_pj
链接:https://juejin.cn/post/6844903830442737671
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 其次定义AOP
// 1. 定义切面
@Aspect
@Component
public class LockMethodAspect {@Autowiredprivate RedisLockHelper redisLockHelper;@Autowiredprivate JedisUtil jedisUtil;private Logger logger = LoggerFactory.getLogger(LockMethodAspect.class);// 2. 定义通知为Aroud类型// 3. 定义使用@RedisLock来定义切入点@Around("@annotation(com.redis.lock.annotation.RedisLock)")public Object around(ProceedingJoinPoint joinPoint) {Jedis jedis = jedisUtil.getJedis();MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();RedisLock redisLock = method.getAnnotation(RedisLock.class);String value = UUID.randomUUID().toString();String key = redisLock.key();// 4. 实现增强代码try {final boolean islock = redisLockHelper.lock(jedis,key, value, redisLock.expire(), redisLock.timeUnit());logger.info("isLock : {}",islock);if (!islock) {logger.error("获取锁失败");throw new RuntimeException("获取锁失败");}try {// 5. 执行目标代码return joinPoint.proceed();} catch (Throwable throwable) {throw new RuntimeException("系统异常");}}  finally {logger.info("释放锁");redisLockHelper.unlock(jedis,key, value);jedis.close();}}
}
  • 最后就可以使用了
@RestController
public class TestController {// 定义切入点@RedisLock(key = "redis_lock")@GetMapping("/index")public String index() {return "index";}
}
  • 辅助类
@Component
public class RedisLockHelper {private long sleepTime = 100;/*** 直接使用setnx + expire方式获取分布式锁* 非原子性** @param key* @param value* @param timeout* @return*/public boolean lock_setnx(Jedis jedis,String key, String value, int timeout) {Long result = jedis.setnx(key, value);// result = 1时,设置成功,否则设置失败if (result == 1L) {return jedis.expire(key, timeout) == 1L;} else {return false;}}/*** 使用Lua脚本,脚本中使用setnex+expire命令进行加锁操作** @param jedis* @param key* @param UniqueId* @param seconds* @return*/public boolean Lock_with_lua(Jedis jedis,String key, String UniqueId, int seconds) {String lua_scripts = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" +"redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end";List<String> keys = new ArrayList<>();List<String> values = new ArrayList<>();keys.add(key);values.add(UniqueId);values.add(String.valueOf(seconds));Object result = jedis.eval(lua_scripts, keys, values);//判断是否成功return result.equals(1L);}/*** 在Redis的2.6.12及以后中,使用 set key value [NX] [EX] 命令** @param key* @param value* @param timeout* @return*/public boolean lock(Jedis jedis,String key, String value, int timeout, TimeUnit timeUnit) {long seconds = timeUnit.toSeconds(timeout);return "OK".equals(jedis.set(key, value, "NX", "EX", seconds));}/*** 自定义获取锁的超时时间** @param jedis* @param key* @param value* @param timeout* @param waitTime* @param timeUnit* @return* @throws InterruptedException*/public boolean lock_with_waitTime(Jedis jedis,String key, String value, int timeout, long waitTime,TimeUnit timeUnit) throws InterruptedException {long seconds = timeUnit.toSeconds(timeout);while (waitTime >= 0) {String result = jedis.set(key, value, "nx", "ex", seconds);if ("OK".equals(result)) {return true;}waitTime -= sleepTime;Thread.sleep(sleepTime);}return false;}/*** 错误的解锁方法—直接删除key** @param key*/public void unlock_with_del(Jedis jedis,String key) {jedis.del(key);}/*** 使用Lua脚本进行解锁操纵,解锁的时候验证value值** @param jedis* @param key* @param value* @return*/public boolean unlock(Jedis jedis,String key,String value) {String luaScript = "if redis.call('get',KEYS[1]) == ARGV[1] then " +"return redis.call('del',KEYS[1]) else return 0 end";return jedis.eval(luaScript, Collections.singletonList(key), Collections.singletonList(value)).equals(1L);}
}

小结

  1. 定义切面,来承载通知和切点。
  2. 定义切点,什么情况下织入增强的代码。
  3. 定义通知/增强代码。
  4. 如果使用注解定义的切点,就给需要增强的连接点加上注解。如果需要增强某一个类的连接点,直接在切点中配置就行了。

代理模式

说到这里就需要说下代理模式以及spring使用的代理模式。

先说结论:

Java中有两种代理,一种是Proxy,另一种是cglib代理。proxy需要接口,cglib代理不需要。因为proxy使用了反射机制,而cglib直接通过ASM操作字节码文件。

JVM层面看代理模式

  • cglib代理

cglib代理通过操作字节码文件把增强代码加入到原来目标类中,从而生成一个新的类,然后载入到内存中,这就是代理类

  • 通过反射的代理:
  1. 定义接口
  2. 实现接口方法
  3. 使用proxy包裹接口,定义钩子函数handler实现增强代码,返回被代理类。
  4. 其中的handler一般会调用被代理类的方法。

而这个调用方法,是使用反射生成的一个被代理对象。

  • 反射的原理:

类加载之后,会在内存中存入Class列表,也就是类定义列表在内存是一种hash结构,全类名到类定义方法区的映射。所以通过全类名可以得到对应的类定义,然后生成对象。

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

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

相关文章

初识Sringboot3+vue3环境准备

环境准备 后端环境准备 下载JDK17https://www.oracle.com/java/technologies/downloads/#jdk17-windows 安装就下一步下一步,选择安装路径 配置环境 环境 JDK17、IDEA2021、maven3.5、vscode 后端 基础&#xff1a;javaSE&#xff0c;javaWeb、JDBC、SMM框架&#xff08;Spr…

Unity JSON编码解码之LitJson 深度剖析

把LitJson的代码库放入到项目中&#xff0c;如图所示:JSON在游戏开发中是一种序列化/反序列化常用的技术&#xff0c;把游戏相关的数据,如地图组成,通过JSON编码&#xff0c;序列化成JSON文本&#xff0c;传输或存储, 要使用的时候再通过JSON技术把文本解析成数据对象&#xff…

竞赛保研 基于卷积神经网络的乳腺癌分类 深度学习 医学图像

文章目录 1 前言2 前言3 数据集3.1 良性样本3.2 病变样本 4 开发环境5 代码实现5.1 实现流程5.2 部分代码实现5.2.1 导入库5.2.2 图像加载5.2.3 标记5.2.4 分组5.2.5 构建模型训练 6 分析指标6.1 精度&#xff0c;召回率和F1度量6.2 混淆矩阵 7 结果和结论8 最后 1 前言 &…

SSM驾校预约管理系统----计算机毕业设计

项目介绍 本项目分为管理员、教练、学员三种角色&#xff0c; 管理员角色包含以下功能&#xff1a; 学员管理、教练管理、车辆管理、关系管理、车辆维修管理、个人中心等功能。 教练角色包含以下功能&#xff1a; 我的课程、我的学员、车辆中心、个人中心等功能。 学员角色包…

跟着LearnOpenGL学习12--光照贴图

文章目录 一、前言二、漫反射贴图三、镜面光贴图3.1、采样镜面光贴图 一、前言 在跟着LearnOpenGL学习11–材质中&#xff0c;我们讨论了让每个物体都拥有自己独特的材质从而对光照做出不同的反应的方法。这样子能够很容易在一个光照的场景中给每个物体一个独特的外观&#xf…

【开源】基于JAVA语言的创意工坊双创管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…

TwIST算法MALTLAB主程序详解

TwIST算法MALTLAB主程序详解 关于TwIST算法的具体原理可以参考&#xff1a; 链接: https://ieeexplore.ieee.org/abstract/document/4358846 链接: https://blog.csdn.net/jbb0523/article/details/52193209 该算法的MATLAB源代码&#xff1a; 链接: http://www.lx.it.pt/~bi…

wireshark access/trunk/hybrid报文分析

1&#xff0c;access接口 发送带vlan的报文 wireshark交换机配置 [Huawei-GigabitEthernet0/0/1] [Huawei-GigabitEthernet0/0/1]port link-type access [Huawei-GigabitEthernet0/0/1]port default vlan 100 [Huawei-GigabitEthernet0/0/2]port link-type access [Huawei-Gig…

【HarmonyOS】鸿蒙开发简介与项目基础配置演示

从今天开始&#xff0c;博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”&#xff0c;对于刚接触这项技术的小伙伴在学习鸿蒙开发之前&#xff0c;有必要先了解一下鸿蒙&#xff0c;从你的角度来讲&#xff0c;你认为什么是鸿蒙呢&#xff1f;它出现的意义又是…

Elasticsearch:升级索引以使用 ELSER 最新的模型

在此 notebook 中&#xff0c;我们将看到有关如何使用 Reindex API 将索引升级到 ELSER 模型 .elser_model_2 的示例。 注意&#xff1a;或者&#xff0c;你也可以通过 update_by_query 来更新索引以使用 ELSER。 在本笔记本中&#xff0c;我们将看到使用 Reindex API 的示例。…

MR实战:实现数据去重

文章目录 一、实战概述二、提出任务三、完成任务&#xff08;一&#xff09;准备数据文件1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 &#xff08;二&#xff09;实现步骤1、Map阶段实现&#xff08;1&#xff09;创建Maven项目&#xff08;2&#xff09;添加相关依赖…

命令模式-实例使用

未使用命令模式的UML 使用命令模式后的UML public abstract class Command {public abstract void execute(); }public class Invoker {private Command command;/*** 为功能键注入命令* param command*/public void setCommand(Command command) {this.command command;}/***…

k8s之陈述式资源管理

1.kubectl命令 kubectl version 查看k8s的版本 kubectl api-resources 查看所有api的资源对象的名称 kubectl cluster-info 查看k8s的集群信息 kubectl get cs 查看master节点的状态 kubectl get pod 查看默认命名空间内的pod的信息 kubectl get ns 查看当前集群所有的命…

Android : 使用GestureOverlayView进行手势识别—简单应用

示例图&#xff1a; GestureOverlayView介绍&#xff1a; GestureOverlayView 是 Android 开发中用于识别和显示手势的视图组件。它允许用户在屏幕上绘制手势&#xff0c;并且应用程序可以检测和响应这些手势。以下是关于 GestureOverlayView 的主要特点&#xff1a; 手势识别…

Large-Precision Sign using PBS

参考文献&#xff1a; [CLOT21] Chillotti I, Ligier D, Orfila J B, et al. Improved programmable bootstrapping with larger precision and efficient arithmetic circuits for TFHE[C]//Advances in Cryptology–ASIACRYPT 2021: 27th International Conference on the T…

使用云渲染节省成本与提升渲染速度的秘诀

我们在提交效果图到云渲染平台时&#xff0c;有时会因为各种原因&#xff0c;如不小心设置错了参数&#xff0c;导致渲染时间变长&#xff0c;渲染费用增加。这不仅增加了项目的成本&#xff0c;还可能影响到整个项目的进度。面对这一问题&#xff0c;炫云提供了小光子、保守优…

Linux第一个小程序-进度条(c语言版)

目录 行缓冲区概念&#xff1a; 行缓冲区代码演示&#xff1a; ​编辑进度条代码 1&#xff1a;memset函数&#xff1a; 2&#xff1a;const char* lable"|/-\\"; 3&#xff1a;usleep C语言 usleep 函数的功能和用法&#xff1a; 4&#xff1a;进度条代码的实…

vue3 组件之间传值

vue3 组件之间传值 非常好&#xff0c;为啥突然开这样一篇博文&#xff0c;首先是因为 vue3 是未来发展的趋势。其次&#xff0c;vue 官方已经确认&#xff0c;将于2023年最后一天停止对 vue2 项目的维护&#xff0c;这个是官方发出的通知&#xff0c;并且呢&#xff0c;尤雨溪…

基于Java网上点餐系统设计与实现

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

静物摄影在UE5里运用几点记要

被摄体&#xff0c;相机与光源的关系&#xff0c;要增强立体感&#xff0c;摄像机与光源的位置关系要错开&#xff1b;b的立体感要更强 漫反射与点光源&#xff0c;UE5太阳光属于漫反射&#xff0c;整体比较柔和&#xff0c;但是阴影处比较黑&#xff1b;摄影棚会用反光板来增亮…