Spring-AOP-5种通知
一、AOP术语
-
连接点
类里面的那些可以被增强的方法,这些方法称为连接点 -
切入点
实际被正真增强的方法,称为切入点
一个类里面有四个方法,但是只增强两个,那么这两个就是切入点
- 通知(增强)
实际增强的逻辑部分称为通知(增强),其中通知有五种类型。
就是增加的部分,比如简约的登录功能,在功能里加入的权限判断就是增强的部分。
- ① 前置通知:切入点方法执行之前执行的方法@Before
- ② 返回通知:切入点方法执行之后执行的方法@AfterReturning:可以得到切入点执行的返回值,有异常后就不执行
- ③ 环绕通知:切入点前后都执行 @Around
- ④ 异常通知:切入发点方法执行异常后执行的方法@AfterThrowing:切入点里面的出现异常如10/0,才会执行的方法。
- ⑤ 后置通知:相当于Java中的try/cath中的finally,不论前面执行结果如何,都会执行的方法 @After:执行后执行,有没有日常都执行。
-
切面
(动词)
把通知应用到切入点 -
切入点表达式
切入点表达式的作用:知道对那个类里面的哪个方法进行增强
语法结构:
execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]))
二、AOP实践-AspectJ
- 依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>
- Spring配置文件
proxy-target-class="true"
表示使用cglib动态代理
实现动态代理有两种形式:
① jdk动态代理:根据目标类接口获取代理类实现规则,生成代理对象。这个代理对象,也是目标类接口的一个实现类。
② cglib动态代理:根据目标类本身获取代理类实现规则,生成代理对象。这个代理对象,也是目标类的一个子类。 (如果目标类为final,则不能使用CGLib实现动态代理)
SpringAOP可以自动在jdk动态代理和CGLib动态代理之间进行切换,规则如下:
- 如果目标对象实现了接口,采用jdk动态代理实现aop。
- 如果目标对象没有实现接口,采用CGLib动态代理实现aop。
- 如果目标对象实现了接口,但仍然想要使用CGLIB实现aop,可以手动进行配置。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <!--开启注解扫描,设置需要扫描的包 --> <context:component-scan base-package="com.du.AopTest.anno"/> <!-- 声明自动为spring容器中那些配置@Aspect切面的bean创建代理,织入切面。 --> <aop:aspectj-autoproxy/> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
- 通知
package com.du.AopTest.anno; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component @Aspect public class UserAop { @Pointcut("execution(* com.du.AopTest.anno.User.eat(..))") public void exe() {} @Before(value = "exe()") public void before(){ System.out.println("before......"); } @After(value = "exe()") public void after() { System.out.println("after......"); } @AfterReturning(pointcut = "exe()",returning = "result") public void afterReturning(Object result) { System.out.println("afterReturning......"); System.out.println("afterReturning-result:"+result); } @AfterThrowing(pointcut = "exe()",throwing = "ex") public void afterThrowing() { System.out.println("AfterThrowing......"); System.out.println("ex"); } @Around(value = "exe()") public void around(ProceedingJoinPoint p) throws Throwable{ System.out.println("around......前"); Object object = p.proceed(); System.out.println("around......object:"+object); System.out.println("around......后"); } }
- Test
public class UserMain { public static void main(String[] args) { ClassPathXmlApplicationContext c = new ClassPathXmlApplicationContext("config.xml"); User user = c.getBean("user",User.class); user.eat(); } }
关于切入点方法,就一个类,里面一个方法
5. 控制台
-
没有异常出现
-
切入点方法有异常出现
- 注意JoinPoint可以得到很多信息
如果你给通知加个形参
package com.du.AopTest.anno; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component @Aspect public class UserAop { @Pointcut("execution(* com.du.AopTest.anno.User.eat(..))") public void exe() {} @Before(value = "exe()") public void before(JoinPoint j){ System.out.println("before......"); Signature s = j.getSignature(); System.out.println(s.getName()); System.out.println(s.toString()); System.out.println(s.getModifiers()); } }
结果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理