Spring AOP
是 Spring 框架的一个核心模块,基于面向切面编程(AOP)思想,用于将横切关注点(如日志、事务、异常处理)从业务逻辑中分离出来,实现代码解耦。
它是高层应用框架,底层依赖 Java 代理技术(JDK 动态代理或 CGLIB),但提供了更丰富的功能和更简洁的使用方式。


XML配置
写一个组件@Component
比如是置前通知
这里的JoinPoint joinPoint是切入点可以获取被切入的方法的一些消息,比如,方法名signature.getName(),参数列表joinPoint.getArgs();
public void beforeLog(JoinPoint joinPoint){
Signature signature=joinPoint.getSignature();
System.out.println("方法名称;"+signature.getName());
Object[] args=joinPoint.getArgs();
for(Object o:args){
System.out.println("参数: " +o);
}
System.out.println("执行前================");
}
如果是异常或者返回值后接入的话们可以带返回值入参,Object result,和异常错误入参Throwable e
public void after_ReturnLog(JoinPoint joinPoint,Object result)
public void after_ThrowLog(JoinPoint joinPoint,Throwable e)
切入方法
比如一下类的eat(String name)方法
@Service
public class StudentService {
public String eat(String name){
System.out.println("正在吃:" + name);
return "返回值:" + name;
}
public void sleep(String name){
System.out.println("正在睡:" + name);
}
public void run(String name){
System.out.println("正在跑:" + name);
}
public void jump(String name){
System.out.println("正在跳:" + name);
}
}
配置xml文件
<?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.xsd
">
<context:component-scan base-package="com.test"/>
<aop:config>
<aop:aspect ref="logAdvice">
<aop:before method="beforeLog" pointcut="execution(* com.test.Service.StudentService.eat(String))"/>
<aop:after method="afterLog" pointcut="execution(* com.test.Service.StudentService.eat(String))"/>
<aop:after-returning method="after_ReturnLog" pointcut="execution(* com.test.Service.StudentService.eat(String))" returning="result"/>
<aop:after-throwing method="after_ThrowLog" pointcut="execution(* com.test.Service.StudentService.eat(String))" throwing="e"/>
</aop:aspect>
</aop:config>
</beans>扫描组件
<context:component-scan base-package="com.test"/>
开始配置aop
<aop:config> </aop:config>
定义一个「切面」
<aop:aspect ref="logAdvice">
作用:定义一个「切面」,ref="logAdvice" 表示这个切面的逻辑由 Spring 容器中名为 logAdvice 的 Bean 提供(即你的 LogAdvice 类,需要用 @Component 或 XML 配置注入容器)。
切面(Aspect):存放通用逻辑(如日志)的类,这里就是 LogAdvice 类。
四个通知标签
<aop:before>(前置通知)
作用:在「目标方法执行前」自动调用 logAdvice 类中的 beforeLog 方法。
参数说明:
method="beforeLog":LogAdvice 类中必须有一个 beforeLog() 方法(可以带参数,需配合切入点表达式传递)。
pointcut:切入点表达式,定义 “要对哪个方法生效”。这里的 execution( com.test.Service.StudentService.eat(String)) 表示:只对 com.test.Service.StudentService 类中,参数为 String 类型的 eat 方法生效。 表示任意返回类型
...
其它,如返回后通知,或者异常报错通知,需要在后面再次增加参数如returning="result",throwing="e"
<aop:after-returning method="after_ReturnLog" pointcut="execution(* com.test.Service.StudentService.eat(String))" returning="result"/>
<aop:after-throwing method="after_ThrowLog" pointcut="execution(* com.test.Service.StudentService.eat(String))" throwing="e"/>
指定包指定类下面的所有方法,比如UserService类下面的所有方法
<aop:before method="logbefore" pointcut="execution(* com.xy.Service.UserService.*(..))"></aop:before>指定包所有类下面的所有方法,比如UserService类下面的所有方法
<aop:before method="logbefore" pointcut="execution(* com.xy.Service.*.*(..))"></aop:before>抽取切点表达式,后续使用pointcut-ref引入
<context:component-scan base-package="com.xy"/>
<aop:config>
<aop:pointcut id="pointcut1" expression="execution(* com.xy.Service.*.*(..))"/>
<aop:aspect ref="logAdvice">
<aop:before method="logbefore" pointcut-ref="pointcut1"></aop:before>
</aop:aspect>
</aop:config>
方便后续使用
<aop:config>
<!-- 单独定义切入点:一次定义,全局复用 -->
<aop:pointcut id="pointcut1" expression="execution(* com.xy.Service.*.*(..))"/>
<aop:aspect ref="logAdvice">
<!-- 前置通知:引用已定义的切入点 -->
<aop:before method="logbefore" pointcut-ref="pointcut1"/>
<!-- 后置通知:直接引用同一个切入点(无冗余) -->
<aop:after method="logafter" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>环绕通知
配置xml
aop:around
<aop:around method="aroundLog" pointcut-ref="pointcut1"></aop:around>
编写环绕通知切入方法
public Object aroundLog(ProceedingJoinPoint joinPoint){
System.out.println("环绕通知=========");
Signature signature=joinPoint.getSignature();
System.out.println("被切入的方法是"+signature.getName());
Object[] args=joinPoint.getArgs();
try{
System.out.println("【前置通知】====");
Object result=joinPoint.proceed(args);
System.out.println("【后置通知】====");
System.out.println("方法返回结果 "+result);
System.out.println("中间其余操作");
System.out.println("【最终通知】====");
return result;
}catch (Throwable e){
System.out.println("【异常通知】====");
e.printStackTrace();
}
return null;
}环绕类型接收的参数为ProceedingJoinPoint类型
joinPoint.proceed(args);为执行该方法
执行以后就触发后,可写后置通知
后置通知后,可以写一些其它代码,然后再最终通知;
如果异常的话,会到catch (Throwable e){}代码块通知
环绕的异常通知
注解配置

前置通知
@Before("pointCut()")
最终通知,方法正常返回以后才通知
@AfterReturning(value = "pointCut()",returning = "result")
后置通知
@After("pointCut()")
异常通知
@AfterThrowing(value="pointCut()",throwing="th")
环绕类型
@Around(value = "pointCut()")步骤
在XML配置注解支持
<aop:aspectj-autoproxy/>

异常通知
完整代码
@Component
@Aspect
public class LogAdvice2 {
@Pointcut("execution(* com.xy.Service.UserService.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void before(JoinPoint joinPoint){
System.out.println("-----前置通知-----");
Signature signature=joinPoint.getSignature();
System.out.println("被切入的方法是"+signature.getName());
Object[] args=joinPoint.getArgs();
System.out.println("参数:"+ Arrays.deepToString(args));
}
@AfterReturning(value = "pointCut()",returning = "result")
public void returning(JoinPoint joinPoint,Object result){
System.out.println("-----最终通知-----");
Signature signature=joinPoint.getSignature();
System.out.println("被切入的方法是"+signature.getName());
Object[] args=joinPoint.getArgs();
System.out.println("参数:"+ Arrays.deepToString(args));
System.out.println("返回值->【"+result+"】");
}
@After("pointCut()")
public void after(JoinPoint joinPoint){
System.out.println("-----后置通知-----");
Signature signature=joinPoint.getSignature();
System.out.println("被切入的方法是"+signature.getName());
Object[] args=joinPoint.getArgs();
System.out.println("参数:"+ Arrays.deepToString(args));
}
@AfterThrowing(value="pointCut()",throwing="th")
public void throwingn(JoinPoint joinPoint,Throwable th){
System.out.println("-----异常通知-----");
Signature signature=joinPoint.getSignature();
System.out.println("被切入的方法是"+signature.getName());
Object[] args=joinPoint.getArgs();
System.out.println("参数:"+ Arrays.deepToString(args));
System.out.println("错误信息->【"+th+"】");
}
}不使用XML开启Aop
编写配置类
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages={"com.xy"})
public class AopConfig {
}
引入Bean
@Test
public void test1(){
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AopConfig.class);
UserService userService=context.getBean(UserService.class);
userService.play("孙悟空");
}环绕类型
@Around(value = "pointCut()")
public Object around(ProceedingJoinPoint joinPoint){
Signature signature=joinPoint.getSignature();
System.out.println("方法名称"+signature.getName());
Object[] args=joinPoint.getArgs();
System.out.println("参数:"+Arrays.deepToString(args));
System.out.println("---------------------------");
try{
System.out.println("前置通知");
Object result= joinPoint.proceed(args);
System.out.println("最终通知");
return result;
}catch (Throwable e){
System.out.println(e);
System.out.println("异常通知");
}finally {
//后置通知需要加Finally
System.out.println("后置通知");
}
return null;
}




评论已关闭