aop详解
1、概述
提供声明式,允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能。例add()加日志功能,这个地方就是横切关注点
- 切面:横切关注点被模块化的对象,一个类。例:log类
- 通知:切面要完成的工作。类中的方法。例:log中的方法
- 五大通知执行顺序
- Spring4.0
正常情况:环绕前置=@Before目标方法执行=环绕返回=环绕最终=@After=@AfterReturning
异常情况:环绕前置=@Before目标方法执行=环绕异常=环绕最终=@After=====@AfterThrowing - Spring5.28
正常情况:环绕前置=@Before=目标方法执行=@AfterReturning=@After=环绕返回=环绕最终
异常情况:环绕前置=@Before=目标方法执行=@AfterThrowing=@After=环绕异常=环绕最终
- Spring4.0
- 五大通知执行顺序
- 目标: 被通知的对象
- 代理:代理类
- 切入点: 切面通知指定的地点
- 连接点:与切入点匹配的执行点
2、使用
2.1、方式1:>Spring的API接口
1.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.moral.service.UserServiceImpl"/>
<bean id="log" class="com.moral.log.Log"/>
<bean id="afterLog" class="com.moral.log.AfterLog"/>
<!--方式一:原生SpringAPI接口-->
<!--配置aop-->
<aop:config>
<!--切入点 expression:表达式,execution(要执行的位置! * * * * *) .方法(参数)-->
<aop:pointcut id="pointCut" expression="execution(* com.moral.service.UserServiceImpl.*(..))"/>
<!--执行环绕增强-->
<!--哪个类切入到哪里-->
<aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointCut"/>
</aop:config>
</beans>
2.AfterLog
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);
}
}
3.Log
public class Log implements MethodBeforeAdvice {
/*
* method:要执行的目标对象的方法
* args:参数
* target:目标对象
* */
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
4.Test
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
2.2、方式:2:自定义类实现AOP
1.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--方式2:自定义类,(切面)-->
<bean id="diy" class="com.moral.diy.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.moral.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
2.切面类
public class DiyPointCut {
public void before(){
System.out.println("===方法执行前===");
}
public void after(){
System.out.println("===方法执行后===");
}
}
3.Test
//方式2
@Test
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
2.3、方式3:注解实现AOP
1.xml
<!--方式3:注解-->
<bean id="annotationPointCut" class="com.moral.diy.AnnotationPointCut"/>
<!--开启注解支持,默认jdk实现(false)->proxy-target-class="false";true:cglib-->
<aop:aspectj-autoproxy/>
2.切面类
@Aspect
public class AnnotationPointCut {
//execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表)),这里修饰符忽略
@Before("execution(* com.moral.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* com.moral.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
@Around("execution(* com.moral.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
//方法执行
Object o = joinPoint.proceed();
System.out.println("环绕后");
}
}
3.Test
//方式3:注解
/*
* 执行结果:
1.环绕前
2.方法执行前
3.添加了一个用户
4.方法执行后
5.环绕后
* */
@Test
public void test03(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY