spring中AspectJ的使用
AspectJ:
什么是AOP:
AOP为Aspect Oriented Programming,意为:面向切面编程;它是一种思想一种设计典范(同Ioc);它是OOP(面向对象编程)的一种衍生。通过AOP对业务逻辑进行隔离,可以降低各个业务逻辑之间的耦合度。AOP主要解决的是”系统及服务“和”主业务逻辑“之间的耦合;
AOP和AspctJ:
AspecJ是一个基于java的AOP框架;spring自身也实现了AOP,在spring中一般使用AspectJ;
关系:AspectJ是AOP思想的实现,AOP实现方式有很多,著名的有spring AOP ,AspectJ;
AOP术语
-
目标类(target):需要被增强的类;
-
连接点(joinpoint):是指可以被增强到的方法;
-
切入点(Pointcut):已经被增强的方法(属于连接点中的方法)
-
通知(advice):指被增强的内容;
-
切面(Aspect):切面=切入点+通知;
-
织入(weaving):把“通知”应用到“目标类”中的过程;
通知的类型
- before:前置通知(应用:各种校验)
- 在方法执行前执行,如果通知抛出异常,阻止方法运行
- afterReturning:后置通知(应用:常规数据处理)
- 方法正常返回后执行,如果方法中抛出异常,通知无法执行
- 必须在方法执行后才执行,所以可以获得方法的返回值。
- around:环绕通知(应用:十分强大,可以做任何事情)
- 方法执行前后分别执行,可以阻止方法的执行
- 必须手动执行目标方法
- afterThrowing:抛出异常通知(应用:包装异常信息)
- 方法抛出异常后执行,如果方法没有抛出异常,无法执行
- after:最终通知(应用:清理现场)
- 方法执行完毕后执行,无论方法中是否出现异常
切入点表达式
基本格式:
execution( 修饰符 返回值 包.类.方法名(参数) throws异常 )
括号中的内容其实就是声明一个方法。通常”修饰符“和”throw 异常“省略不写;
返回值:
基本类型,对象 *//(匹配任意返回值)
包:用限定名。可以使用通配符如:
com.abc.service//表示固定包 com.abc.crm.*.service//表示crm包下任意子包的service包 com.abc.crm..//表示crm包下面的所有子包(包括自己) “..”可以表示自己本身和自己下面的多级包
类:可以使用固定名称,和统配符号
*Impl //以Impl结尾 User* //以User开头的 * //任意
方法名
addUser//固定方法 add*//以add开头 *Do//以Do结尾
参数
()//无参 (int)//一个整型 (int,int)//两个 (..)//参数任意
例子
execution(* *.someServiceImpl.*(..)) //所有的包下面(限定一级包)someServiceImpl类的所有任意参数的方法 execution(* *..someServiceImpl.*(..)) //所有的包下面(可以是多级包)someServiceImpl类的所有任意参数的方法 execution(* com.abc.crm.*.service..*.*(..)) //service下自己以及自己的子包的任意类的任意方法
基于xml的AspectJ编程
导入jar包
导入四个jar包
- AspectJ的jar包
- spring用于整合aspectJ的jar包
- spring的AOP实现jar包
- AOP联盟的AOP规范jar包
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency>
定义切面类
定义切面类用于写对应通知的方法
public class MyAspect { public void before(){ System.out.println("执行前置通知before()!"); } //可以输出当前的连接点 public void before2(JoinPoint jp){ System.out.println("执行前置通知before2() jp = "+ jp); } public void afterReturning(){ System.out.println("执行后置通知afterReturning()!"); } //result接收目标方法的返回结果 //后置通知不能修改目标返回的返回结果本身 public void afterReturning2(Object res){ System.out.println("执行后置通知afterReturning2()目标方法的返回结果为result = "+ res +"aaa"); } //环绕通知中来调用目标方法确定目标方法的执行时间 //环绕通知可以改变目标方法的返回结果本身 public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("执行环绕通知-目标方法执行之前!"); //目标方法执行 Object proceed = pjp.proceed(); System.out.println("执行环绕通知-目标方法执行之后"); if (proceed != null){ proceed = proceed.toString().toUpperCase(); } return proceed; } public void afterThrowing(){ System.out.println("执行异常通知afterThrowing()"); } public void afterThrowing2(Exception ex){ System.out.println("执行异常通知afterThrowing2() ex = "+ex); } public void after(){ System.out.println("执行最终同时after()"); } }
引入约束
引入spring对aop的约束即可
AOP配置
<!--注册切面:交叉业务逻辑对象--> <bean id="myAspect" class="com.abc.service.MyAspect"/> <aop:config> <!--定义切入点表达式--> <aop:pointcut id=" " expression=""/> <aop:pointcut id=" " expression=""/> <!--配置切面--> <!--切面为切入点+通知--> <aop:aspect ref="myAspect"> <!--前置通知,引用切入点表达式--> <aop:before method=" " pointcut-ref=""/> <!--后置通知--> <aop:after-returning method=" " pointcut-ref=" " returning="res"/> <!--环绕通知--> <aop:around method=" " pointcut-ref=" "/> <!--异常通知--> <aop:after-throwing method=" " pointcut-ref=" "/> <!--最终通知--> <aop:after method=" " pointcut-ref=" "/> </aop:config>
基于注解的AspectJ编程
-
导入jar包
-
定义切面类
-
引入约束
-
注册AspectJ自动代理生成器
<!--注册aspectj的自动代理--> <aop:aspectj-autoproxy/> -
在切面类中添加注解
//切面:交叉业务逻辑 @Aspect //该类是切面类 public class MyAspect { @Before("doFirstPC()") public void before(){ System.out.println("执行前置通知before()!"); } @Before("doAllPC()") public void before2(JoinPoint jp){ System.out.println("执行前置通知before2() jp = "+ jp); } @AfterReturning("doSecondPC()") public void afterReturning(){ System.out.println("执行后置通知afterReturning()!"); } //result接收目标方法的返回结果 //后置通知不能修改目标返回的返回结果本身 @AfterReturning(value = "doSecondPC()",returning = "res") public void afterReturning2(Object res){ System.out.println("执行后置通知afterReturning2()目标方法的返回结果为result = "+ res +"aaa"); } //环绕通知中来调用目标方法确定目标方法的执行时间 //环绕通知可以改变目标方法的返回结果本身 @Around("doThirdPC()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("执行环绕通知-目标方法执行之前!"); //目标方法执行 Object proceed = pjp.proceed(); System.out.println("执行环绕通知-目标方法执行之后"); if (proceed != null){ proceed = proceed.toString().toUpperCase(); } return proceed; } @AfterThrowing("doSecondPC()") public void afterThrowing(){ System.out.println("执行异常通知afterThrowing()"); } @AfterThrowing(value = "doSecondPC()",throwing = "ex") public void afterThrowing2(Exception ex){ System.out.println("执行异常通知afterThrowing2() ex = "+ex); } @After("doSecondPC()") public void after(){ System.out.println("执行最终同时after()"); } @Pointcut("execution(* *..SomeServiceImpl.doFirst())") public void doFirstPC(){}; @Pointcut("execution(* *..SomeServiceImpl.doSecond())") public void doSecondPC(){}; @Pointcut("execution(* *..SomeServiceImpl.doThird())") public void doThirdPC(){}; @Pointcut("execution(* *..SomeServiceImpl.*())") public void doAllPC(){}; }
posted on 2019-11-13 15:14 passionConstant 阅读(1453) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程