Spring AOP<一>简介与基础使用
spring AOP
基础定义
含义 | 使用 | |
---|---|---|
切面 | 组织多个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);}
}
小结
- 定义切面,来承载通知和切点。
- 定义切点,什么情况下织入增强的代码。
- 定义通知/增强代码。
- 如果使用注解定义的切点,就给需要增强的连接点加上注解。如果需要增强某一个类的连接点,直接在切点中配置就行了。
代理模式
说到这里就需要说下代理模式以及spring使用的代理模式。
先说结论:
Java中有两种代理,一种是Proxy,另一种是cglib代理。proxy需要接口,cglib代理不需要。因为proxy使用了反射机制,而cglib直接通过ASM操作字节码文件。
JVM层面看代理模式
- cglib代理
cglib代理通过操作字节码文件,把增强代码加入到原来目标类中,从而生成一个新的类,然后载入到内存中,这就是代理类。
- 通过反射的代理:
- 定义接口
- 实现接口方法
- 使用proxy包裹接口,定义钩子函数handler实现增强代码,返回被代理类。
- 其中的handler一般会调用被代理类的方法。
而这个调用方法,是使用反射生成的一个被代理对象。
- 反射的原理:
类加载之后,会在内存中存入Class列表,也就是类定义列表在内存是一种hash结构,全类名到类定义方法区的映射。所以通过全类名可以得到对应的类定义,然后生成对象。
相关文章:

Spring AOP<一>简介与基础使用
spring AOP 基础定义 含义使用切面组织多个Advice,Advice放在切面中定义。也就是说是定义通知的自定义类。自定义的AOP类Aspect连接点方法调用,异常抛出可以增强的点JoinPoint :也就是**被增强的方法的总称,可以获取具体方法的信息ÿ…...
react ant tree节点没有children也会显示展开框 节点有children却不显示展开框
1.背景 最近处理树状结构时遇到了一个诡异问题,后端返回了组织树,组织树里面可能有组织,也可能有用户,很奇怪的是所有用户都会显示展开图标,而组织有些会显示展开图标,有些不会显示 2.分析 一开始找到了用…...

【Linux】进程查看|fork函数|进程状态
🦄 个人主页——🎐开着拖拉机回家_Linux,大数据运维-CSDN博客 🎐✨🍁 🪁🍁🪁🍁🪁🍁🪁🍁 🪁🍁🪁&am…...
LeetCode第98题 - 有效的括号
题目 解答 方案一 class Solution {public boolean isValidBST(TreeNode root) {if (root null) {return true;}if (root.left null && root.right null) {return true;}if (root.left ! null && root.left.val > root.val) {return false;}if (root.…...

Nacos学习思维导图
一、服务注册 参考文档:http://www.bryh.cn/a/118936.html https://blog.csdn.net/Saintmm/article/details/121981184 二、服务续约 参考文档:http://www.bryh.cn/a/118936.html https://blog.csdn.net/Saintmm/article/details/121981184 三、服务…...
新视野英语课本复盘1
the triumpth of years of hard work 多年的辛勤付出的胜利 get by on very little sleep 靠很少的睡眠勉强维持生活或工作 pursue new passions 追求新的热爱之事 reap the benefits of this opportunity 收获这个机会带来的益处 you will not only emerge as a more broadly …...
Sentinel整合OpenFeign
1、配置文件 feign:sentinel:enabled: true 2、 编写一个工厂类 import com.cart.cartservice.client.ItemClient; import com.cart.cartservice.entity.Item; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.openfeign.FallbackFactory; import org.sp…...

PyTorch实战:基于Seq2seq模型处理机器翻译任务(模型预测)
文章目录 引言数据预处理加载字典对象en2id和zh2id文本分词 加载训练好的Seq2Seq模型模型预测完整代码结束语 引言 随着全球化的深入,翻译需求日益增长。传统的人工翻译方式虽然质量高,但效率低,成本高。机器翻译的出现,为解决这…...

stm32学习总结:5、Proteus8+STM32CubeMX+MDK仿真串口并使用串口打印日志(注意重定向printf到串口打印的问题)
stm32学习总结:5、Proteus8STM32CubeMXMDK仿真串口并使用串口打印日志(注意重定向printf到串口打印的问题) 文章目录 stm32学习总结:5、Proteus8STM32CubeMXMDK仿真串口并使用串口打印日志(注意重定向printf到串口打印…...

SAFe大规模敏捷企业级实训
课程简介 SAFe – Scaled Agile Framework是目前全球运用最广泛的大规模敏捷框架,也是成长最快、最被认可、最有价值的规模化敏捷框架,目前全球SAFe认证专业人士已达80万人,福布斯100强的70%都在实施SAFe。本课程是一个2天的 SAFe权威培训课…...

中医电子处方系统,西医个体诊所门诊卫生室病历记录查询软件教程
中医电子处方系统,西医个体诊所门诊卫生室病历记录查询软件教程 一、软件程序问答 1、电子处方软件如何快速开单? 如下图,软件以 佳易王诊所电子处方管理系统V17.1版本为例说明 在开电子处方的时候可以按单个药品开,也可以直…...
搞定ESD(八):静电放电之原理图设计
文章目录 一、防护对象识别方法1.1 根据应用手册识别防护对象1.2 根据端口信号类型识别防护对象1.3 根据信号类型识别防护对象二、电路级ESD防护设计2.1 静电尖峰脉冲电压钳位设计(ESD器件并联)2.1.1 高速差分信号ESD防护设计2.1.2 低速信号ESD防护设计2.2 静电放电电流限制设…...
微前端 Micro App
MicroApp 官网链接 MicroApp 链接...
Java amr格式转mp3格式
1.问题描述 微信返回的语音是amr格式的,浏览器不能直接使用,所以需要转为mp3 注意:不能直接使用IO流转为mp3,不然H5还是用不了。转换之后的语音只能在播放器上播放,内里的文件格式其实还是amr 2.使用以下方式转换 音…...
Vue2面试题:说一下虚拟DOM的原理?
虚拟dom是对真实dom的抽象,本质是JS对象 在生成真实DOM之前,vue会把模板编译为一个虚拟dom,当里面某个DOM节点发生变动时,通过diff算法对比新旧虚拟DOM,发现不一样的地方直接修改在真实的DOM上 优点: 可以…...

Spring对bean的管理
一.bean的实例化 1.spring通过反射调用类的无参构造方法 在pom.xml文件中导入坐标: <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.29<…...

Character Controller Smooth
流畅的角色控制器 Unity的FPS解决方案! 它是一种具有非常平滑运动和多种设置的解决方案: - 移动和跳跃 - 坐的能力 - 侧翻角度 - 不平整表面的处理 - 惯性守恒 - 重力 - 与物理物体的碰撞。 - 支持没有家长控制的平台 此解决方案适用于那些需要角色控制器…...

企业内训系统源码开发实战:搭建实践与经验分享
本篇文章中,小编将带领读者深入探讨企业内训系统的源码开发实战,分享在搭建过程中遇到的挑战与解决方案。 一、项目规划与需求分析 通过对企业内训需求的深入了解,我们可以更好地定义系统架构和数据库设计。 二、技术栈选择 在内训系统开发…...
15.三数之和(双指针,C解答附详细分析)
题目描述: 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含…...

SpringCloud微服务 【实用篇】| Dockerfile自定义镜像、DockerCompose
目录 一:Dockerfile自定义镜像 1. 镜像结构 2. Dockerfile语法 3. 构建Java项目 二: Docker-Compose 1. 初识DockerCompose 2. 部署微服务集群 前些天突然发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...

GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...