13-实现springAop的3种方式
aop实现方式1(实现spring接口)
导包
使用之前要导入依赖包
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> </dependencies>
项目结构:
1 2 3 4 5 6 7 8 9 10 11 12 | spring1-aop ├───.idea ├───src │ ├───main │ │ ├───java │ │ │ └───com │ │ │ └───ajream │ │ │ ├───log │ │ │ └───service │ │ └───resources │ └─── test └───java |
业务模块service
被代理的接口,包含了要实现的具体功能
UserService.java接口:
package com.ajream.service; public interface UserService { void add(); void delete(); void update(); void query(); }
UserServiceImpl.java
package com.ajream.service; public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("增加一个用户"); } @Override public void delete() { System.out.println("删除一个用户"); } @Override public void update() { System.out.println("修改一个用户"); } @Override public void query() { System.out.println("查询一个用户"); } }
代理模块
在原有基础上扩展一些功能
Log.java (在实现某个业务(调用某个方法)前,打印一些相关信息)
说明:重写MethodBeforeAdvice接口的before方法,说明在切入点之前执行这个方法
package com.ajream.log; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class Log implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { assert target != null; System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了"); } }
AfterLog.java (在实现某个业务(调用某个方法)后,打印一些相关信息)
说明:重写AfterReturningAdvice的
afterReturning
方法,说明在切入点之后执行这个方法
package com.ajream.log; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了" +method.getName()+ "方法,返回值为:"+returnValue); } }
ApplicationContext.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id="userService" class="com.ajream.service.UserServiceImpl" /> <bean id="log" class="com.ajream.log.Log" /> <bean id="afterLog" class="com.ajream.log.AfterLog" /> <aop:config> <!-- 定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数)) "*"表示任意 --> <aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/> <!-- 执行环绕增加--> <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" /> <aop:advisor advice-ref="log" pointcut-ref="pointCut"/> </aop:config> </beans>
说明:
注意添加aop支持
xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
aop配置(使用原生spring api接口)
<aop:config> <!--定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数)) "*"表示任意 --> <aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/> <!--执行环绕增加,即在切入点前后执行下面的操作--> <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" /> <aop:advisor advice-ref="log" pointcut-ref="pointCut"/> </aop:config>
测试
MyTest.java测试
import com.ajream.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); //动态代理的是接口 UserService userService = context.getBean("userService", UserService.class); userService.add(); } }
测试结果:
Aop实现方式2(自定义切入类)
主要是aop配置方式不同
之前是使用原生spring api方式,分别实现了MethodBeforeAdvice
和AfterReturningAdvice
这两个接口,因此在xml中只需要指明要切入哪个位置,执行什么操作,在执行目标接口的方法时spring就会根据xml配置自动去执行对应操作,如下:
<aop:config> <!--定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数)) "*"表示任意 --> <aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/> <!--执行环绕增加,即在切入点前后执行下面的操作--> <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" /> <aop:advisor advice-ref="log" pointcut-ref="pointCut"/> </aop:config>
现在改用自定义切入面方式:
首先添加一个切面DiyPointCut(即一个类,包含了要切入的方法)
package com.ajream.diy; //自定义切入面 public class DiyPointCut { public void before(){ System.out.println("=====方法执行前======"); } public void after(){ System.out.println("======方法执行后======"); } }
aop配置:
<!--方式2:自定义类--> <bean id="diy" class="com.ajream.diy.DiyPointCut" /> <aop:config> <!--定义切面,ref为要引用的类--> <aop:aspect ref="diy" > <!--切入点--> <aop:pointcut id="point" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/> <!-- aop:before表示在切入点point之前执行切面的before方法--> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point" /> </aop:aspect> </aop:config>
aop实现方式3(使用注解开发)
首先开启aop注解支持
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id="userService" class="com.ajream.service.UserServiceImpl" /> <!--方式3,注解方式--> <bean id="annotationPointCut" class="com.ajream.diy.AnnotationPointCut" /> <!--开启aop注解支持--> <aop:aspectj-autoproxy /> </beans>
添加切面AnnotationPointCut.java类
package com.ajream.diy; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect //标注这是一个切面 public class AnnotationPointCut { @Before("execution(* com.ajream.service.UserServiceImpl.*(..))") //切入位置 public void before(){ System.out.println("=====方法执行前====="); } @After("execution(* com.ajream.service.UserServiceImpl.*(..))") public void after(){ System.out.println("=====方法执行后====="); } @Around("execution(* com.ajream.service.UserServiceImpl.*(..))") //环绕增强 public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); Object proceed = jp.proceed();// 执行方法 System.out.println("执行的方法签名:" + jp.getSignature()); System.out.println("环绕后"); } }
注意,如果添加了环绕增强,首先执行环绕增强,执行了proceed方法后才会触发
@Before
@After
这2个注解的内容,所以输出结果如下:
本文来自博客园,作者:aJream,转载请记得标明出处:https://www.cnblogs.com/ajream/p/15383517.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人