Spring Boot 两种 AOP 拦截方式
2019-02-25 本文已影响0人
LeonardoLiu
0. 构建配置类
调用方法时,为了便于测试,依赖于该空配置类创建一个新的 ApplicationContext
ComponentScan 的包位置为以下 各 Component 所在的包
@Configuration
@ComponentScan("com.example.demo")
public class Config {
}
1. 注解式
1.1 声明注解
创建一个注解,由于需要测试,在运行时调用 Action 的 env 方法,需要将 Retention Policy 从默认的 CLASS 修改为 RUNTIME
package com.example.demo.main;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
String env();
}
1.2 构造 Service,并引用注解
创建 DemoService,在方法 test 上打自定义的 @Action 注解
@Service
public class AnnotationService {
@Action(name = "切面 test")
public void test() {
}
}
1.3 声明 Aspect
声明切面,通过 @Pointcut
注解将自定义的 Action 注解注册为切点。
通过 @After、@Before、@Around 注解设定在切点前后要执行的操作
@Aspect
@Component
public class LogAspect {
@After("@annotation(Action)")
public void after(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
// 默认情况下,注解的 RententionPolicy 是 CLASS,需要修改为 RUNTIME,否则会因运行时找不到该自定义的 Action 注解抛 NULL 异常
Action action = method.getAnnotation(Action.class);
System.out.println("注解式拦截 " + action.env());
}
}
2. 按方法规则
2.1 构造要插入切面的 Service
@Service
public class DemoService {
public void test() {
}
}
2.2 声明 Aspect
声明切面,通过 @Before
、@After、@Around 注解下的 execution
方法指定切点路径,以及在切点前后要执行的操作
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.demo.main.DemoService .*(..))")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法规则式拦截 " + method.getName());
}
}
3. 调用 Service
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 根据 Config 配置类新建一个 ApplicationContext
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
DemoService annotationService = context.getBean(DemoService.class);
annotationService.test();
context.close();
}
}
关于构造切面、设定切点
前面基于注解和基于方法规则的 AOP 拦截构造方法中,都有一个相同的设定切点的过程,即
@Before("execution(* com.example.demo.main.DemoService .*(..))")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法规则式拦截 " + method.getName());
}
这里的 Before 注解使用方法等价于
@Pointcut("execution(* com.example.demo.DemoService.*(..))")
public void methodJointCut() {
}
@Before("methodJointCut()")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法规则式拦截 " + method.getName());
}