本文来详细说下@AspectJ中的几种通知方式
概述
当Spring 2.0发布以后,Spring AOP增加了新的使用方式,Spring AOP集成了AspectJ。我们最常用的就是这个版本的Spring AOP。
主要有如下变化
- 可以用POJO来定义Aspect和Adivce,并提供了一系列相应的注解,如@Aspect和@Around等。而不用像1.x版本中实现相应的接口
- 支持aspectj中的pointcut的表达方式,我们都深有体会哈
通知方式说明
下面这个是官网对@AspectJ中的几种通知方式的说明
一个例子
导入@AspectJ注解的maven
<!-- @Aspect-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
选择连接点,就是业务方法,可以看作动态代理中的目标对象
Spring 是方法级别的 AOP 框架,我们主要也是以某个类额某个方法作为连接点,另一种说法就是:选择哪一个类的哪一方法用以增强功能。
package cn.wideth.buz.test;
public class Landlord {
public void service() {
// 仅仅只是实现了核心的业务功能
System.out.println("业务方法 => service()");
// throw new RuntimeException();
}
}
我们在这里就选择上述 Landlord 类中的 service() 方法作为连接点。
创建切面
选择好了连接点就可以创建切面了,我们可以把切面理解为一个拦截器,当程序运行到连接点的时候,被拦截下来,在开头加入了初始化的方法,在结尾也加入了销毁的方法而已,在 Spring 中只要使用 @Aspect 注解一个类,那么 Spring IoC 容器就会认为这是一个切面了。
package cn.wideth.buz.test;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/***
* 切面(aspect)。类是对物体特征的抽象,
* 切面就是对横切关注点的抽象
*/
@Aspect
public class Broker {
/***
* 连接点(joinpoint)。被拦截到的点,因为Spring只
* 支持方法类型的连接点,所以在Spring中连接点指的就
* 是被拦截到的方法,实际上连接点还可以是字段或者构造器
*/
@Pointcut("execution(* cn.wideth.buz.test.Landlord.service(..))")
public void lService() {
}
/***
* @Before在方法执行之前执行
*/
@Before("lService()")
public void before(){
System.out.println("before()");
}
/***
* @After在方法执行之后执行
*/
@After("lService()")
public void after(){
System.out.println("after()");
}
/***
* @Around围绕着方法执行
*/
@Around("lService()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("<== around");
Object result = joinPoint.proceed();
System.out.println("around ==>");
return result;
}
/***
* @AfterReturning在方法返回结果之后执行
*/
@AfterReturning("lService()")
public void afterReturning(){
System.out.println("AfterReturning()");
}
/***
* @AfterThrowing在方法抛出异常之后执行
*/
@AfterThrowing("lService()")
public void afterThrowing(){
System.out.println("afterThrowing()");
}
}
启用AOP
因为使用注解的方式来操作AOP,所以编写一个配置类来开启AOP
package cn.wideth.buz.test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
// 启用AOP
@EnableAspectJAutoProxy
public class AspectJConfig {
@Bean
public Landlord getLandlord() {
return new Landlord();
}
}
测试 AOP
package cn.wideth.buz.test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AspectJConfig.class, Broker.class);
Landlord landlord = context.getBean(Landlord.class);
landlord.service();
context.close();
}
}
测试结果
Adivce之间的顺序关系
正确的情况下
@Around->@Before->方法执行->@AfterReturning ->@After-> @Around
本文小结
本文介绍了@AspectJ中的几种通知方式,以及5种通知的先后顺序。