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());
    }
上一篇下一篇

猜你喜欢

热点阅读