概念
Advice通知
注入到class文件中的代码。典型的 Advice 类型有 before、after 和 around,分别表示在目标方法执行之前、执行后和完全替代目标方法执行的代码。 除了在方法中注入代码,也可能会对代码做其他修改,比如在一个class中增加字段或者接口。
Joint point(连接点)
程序中可能作为代码注入目标的特定的点,例如一个方法调用或者方法入口。
Pointcut(切入点)
告诉代码注入工具,在何处注入一段特定代码的表达式。例如,在哪些 joint points 应用一个特定的 Advice。切入点可以选择唯一一个,比如执行某一个方法,也可以有多个选择。
实战(springboot整合aspectj)
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
通知类型
-
Before前置通知
在切入点前面执行通知。
-
After后置通知
在切入点方法执行后通知,如果切入点的方法抛出异常,也会进行通知。
-
Around环绕通知
可以在切入点前,切入点后进行通知。可以自定义切入点方法执行前或后执行指定代码。可以用于统计方法执行时间。
-
AfterReturning后置通知
抛出异常不会进行通知,方法正常返回才会进行通知。
-
AfterThrowing异常通知
抛出异常后进行通知。
代码
// 普通类
@Service
public class AspectService {
@ShowRunTime
public void HelloAspectj(String name) {
}
//@AdminSaid
@ShowRunTime
public void said() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 自定义的注解
// 标明该注解可以标注在什么位置上
@Target({ElementType.METHOD,ElementType.FIELD})
// 标明该注解可以保留到什么时候
@Retention(RetentionPolicy.RUNTIME)
// 是否在javadoc中可用
@Documented
public @interface AdminSaid {
}
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ShowRunTime {
}
/**
* 这是一个用于配置切面通知的类
* @Configuration:标明配置类,将切面注入到spring中
* @Aspect:标明一个切面类
*/
@Configuration
@Aspect
public class AnAspect {
// 前置通知:execution(返回值类型 包名.方法名(方法参数))
@Before(value = "execution(* com.sundae.test.springbootdemo.aspectjdemo.AspectService.HelloAspectj(..))")
public void showToast(JoinPoint joinPoint) {
// 通过joinpoint获取参数
Object[] args = joinPoint.getArgs();
System.out.println("通过joinpoint获取参数"+args[0]);
// 通过joinpoint获取joinpoint的类型
System.out.println("通过joinpoint获取joinpoint的类型"+joinPoint.getKind());
Signature signature = joinPoint.getSignature();
System.out.println("方法名"+signature.getName());
System.out.println(joinPoint.getTarget());
}
// 创建一个注解为AdminSaid的切面。
@Pointcut("@annotation(com.sundae.test.springbootdemo.aspectjdemo.AdminSaid)")
public void pointcut() {
}
// 前置通知:在上面切面pointcut()之前进行通知。
@Before("pointcut()")
public void showT() {
System.out.println("AdminSaid!");
}
// 创建一个注解为ShowRunTime的切面。
@Pointcut("@annotation(com.sundae.test.springbootdemo.aspectjdemo.ShowRunTime)")
public void runTimePointCut() {
}
// 创建上面切面的环绕通知。实现了所有添加注解@ShowRunTime的方法都能打印方法运行时间的功能。
// ProceedingJoinPoint:连接点。
@Around("runTimePointCut()")
@AfterThrowing
public void showRunTime(ProceedingJoinPoint joinPoint) throws Throwable {
long before = new Date().getTime();
joinPoint.proceed();
long after = new Date().getTime();
// joinPoint.getSignature().getName()获取方法名称。
System.out.println(joinPoint.getSignature().getName()+"方法运行时间:"+(after-before)+"ms");
}
}