Spring 2.0 @AspectJ 配置
Spring 2.0 以后,引入了 @AspectJ 和 Schema-based 的两种配置方式,我们先来介绍 @AspectJ 的配置方式,之后我们再来看使用 xml 的配置方式。
添加依赖
首先,我们需要依赖 aspectjweaver.jar 这个包,这个包来自于 AspectJ:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.11</version>
</dependency>
如果是使用 Spring Boot 的话,添加以下依赖即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
配置开启aop
其次,我们需要开启 @AspectJ 的注解配置方式,有两种方式:
在 xml 中配置:
<aop:aspectj-autoproxy/>
使用 @EnableAspectJAutoProxy
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
一旦开启了上面的配置,那么所有使用 @Aspect 注解的 bean 都会被 Spring 当做用来实现 AOP 的配置类,我们称之为一个 Aspect。
注意了,@Aspect 注解要作用在 bean 上面,不管是使用 @Component 等注解方式,还是在 xml 中配置 bean,首先它需要是一个 bean。
配置切面
配置 Pointcut
首先,我们需要配置 Pointcut,Pointcut 在大部分地方被翻译成切点,用于定义哪些方法需要被增强或者说需要被拦截
Spring AOP 只支持 bean 中的方法(不像 AspectJ 那么强大),所以我们可以认为 Pointcut 就是用来匹配 Spring 容器中的所有 bean 的方法的。
@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature
我们看到,@Pointcut 中使用了 execution 来正则匹配方法签名,这也是最常用的,除了 execution,我们再看看其他的几个比较常用的匹配方式:
within:指定所在类或所在包下面的方法(Spring AOP 独有)
@Pointcut("within(com.javadoop.springaoplearning.service..*)")
@annotation:方法上具有特定的注解,如 @Subscribe 用于订阅特定的事件。
@Pointcut("execution( .*(..)) && @annotation(com.javadoop.annotation.Subscribe)")
bean(idOrNameOfBean):匹配 bean 的名字(Spring AOP 独有)
@Pointcut("bean(*Service)")
Tips:上面匹配中,通常 “.” 代表一个包名,”..” 代表包及其子包,方法参数任意匹配使用两个点 “..”。
配置 Advice
配置 pointcut 就是配置我们需要拦截哪些方法,接下来,我们要配置需要对这些被拦截的方法做什么。
@Aspect
public class AdviceExample {
// 下面方法就是写拦截 "dao层实现"
@Before("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ... 实现代码
}
// 当然,我们也可以直接"内联"Pointcut,直接在这里定义 Pointcut
// 把 Advice 和 Pointcut 合在一起了,但是这两个概念我们还是要区分清楚的
@Before("execution(* com.javadoop.dao.*.*(..))")
public void doAccessCheck() {
// ... 实现代码
}
@AfterReturning("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
@AfterReturning(
pointcut="com.javadoop.aop.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// 这样,进来这个方法的处理时候,retVal 就是相应方法的返回值,是不是非常方便
// ... 实现代码
}
// 异常返回
@AfterThrowing("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ... 实现代码
}
@AfterThrowing(
pointcut="com.javadoop.aop.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ... 实现代码
}
// 注意理解它和 @AfterReturning 之间的区别,这里会拦截正常返回和异常的情况
@After("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {
// 通常就像 finally 块一样使用,用来释放资源。
// 无论正常返回还是异常退出,都会被拦截到
}
// 感觉这个很有用吧,既能做 @Before 的事情,也可以做 @AfterReturning 的事情
@Around("com.javadoop.aop.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
Spring 2.0 schema-based 配置
本节将介绍的是 Spring 2.0 以后提供的基于
配置 Aspect
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
所有的配置都在
然后,我们写好 Aspect 代码后,将其“织入”到合适的 Pointcut 中,这就是面向切面。、
配置 Pointcut
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.javadoop.springaoplearning.service.*.*(..))"/>
<!--也可以像下面这样-->
<aop:pointcut id="businessService2"
expression="com.javadoop.SystemArchitecture.businessService()"/>
</aop:config>
将
我们也可以在
<aop:config>
<aop:aspect ref="logArgsAspect">
<aop:pointcut id="internalPointcut"
expression="com.javadoop.SystemArchitecture.businessService()" />
</aop:aspect>
</aop:config>