📅  最后修改于: 2023-12-03 15:35:02.842000             🧑  作者: Mango
Spring AOP是Spring框架中非常重要的一个模块,它提供了基于建议的编程方式,可以很好地实现横向切面关注点(cross-cutting concerns)的处理,比如事务管理、安全性校验、缓存、日志等等。在这篇文章中,我们将通过一个XML配置的示例,介绍Spring AOP模块的基本使用。
在开始之前,我们需要在程序中添加Spring AOP的依赖。如果你使用的是Maven或Gradle,可以按照下面的依赖添加到你的pom.xml或build.gradle中。
<!-- Maven -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Gradle -->
compile 'org.springframework:spring-aop:${spring.version}'
为了使用Spring AOP,我们需要在 Spring 配置文件(如 applicationContext.xml)中进行以下配置:
使用 aop:aspectj-autoproxy
标签来启用 AspectJ 自动代理。该标签会在运行时使用 AspectJ 创建代理类,代理被 @Aspect 注解的类。
<aop:aspectj-autoproxy />
使用 aop:config
标签开启切面配置。同时我们需要在 config 里定义一个 aop:aspect
标签来声明一个切面。通过 ref
属性指定切面绑定的切面类。
<aop:config>
<aop:aspect ref="myAspect">
...
</aop:aspect>
<aop:config>
使用 aop:pointcut
标签来声明切点,它定义了一个连接点表达式(Pointcut Expression),该表达式指定了哪些方法需要被拦截。
<aop:pointcut id="businessService" expression="execution(* com.example.service.*.*(..))" />
上面的 expression
的含义是,拦截 com.example.service 包下的所有方法。
使用 aop:advisor
标签来配置通知,pointcut-ref
属性用于引用之前定义的切点。在通知中定义了哪些行为需要在执行目标方法前或后执行。
<aop:advisor advice-ref="myAdvice" pointcut-ref="businessService" />
现在我们要实现一个记录请求耗时的功能,以此来说明Spring AOP的使用。
MyAspect
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
@Around("execution(* com.example.controller.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long totalTime = System.currentTimeMillis() - startTime;
System.out.println(String.format("%s 耗时 %d ms", joinPoint.getSignature(), totalTime));
return proceed;
}
}
这个切面类 MyAspect
注解标注了 @Aspect
,指定它是一个切面类。同时在类中声明了一个公共方法 logExecutionTime
,这个方法使用了 @Around
注解,表示它是一个环绕通知。环绕通知会在目标方法执行前后都执行,这里我们使用 ProceedingJoinPoint
来捕捉目标方法,调用 proceed()
后才会执行目标方法。
在方法中,我们记录了请求开始时间,然后调用 proceed()
执行目标方法,接着计算总耗时,并将日志输出到控制台。
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启AOP -->
<aop:aspectj-autoproxy />
<!-- 声明切面 -->
<bean id="myAspect" class="com.example.aspect.MyAspect" />
<!-- 声明切点 -->
<aop:pointcut id="controllerMethods" expression="execution(* com.example.controller.*.*(..))" />
<!-- 配置通知 -->
<aop:advisor advice-ref="myAspect" pointcut-ref="controllerMethods" />
</beans>
这个 applicationContext.xml
配置文件中包含了上述的三个配置部分,并通过 bean
标签声明了 MyAspect
,然后使用 aop:pointcut
声明了切点 controllerMethods
,它包含了 com.example.controller
包下所有方法。最后使用 aop:advisor
配置了 myAspect
,在切点 controllerMethods
上生效。
通过上述示例和解释,我们学习了Spring AOP的基本使用和配置。AOP可以帮助我们解决许多问题(如对日志、监控、缓存、事务等的封装),使代码具备更好的可重用性和可维护性。