美文网首页
Spring Boot 两种 AOP 拦截方式

Spring Boot 两种 AOP 拦截方式

作者: LeonardoLiu | 来源:发表于2019-02-25 14:34 被阅读0次

    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());
        }
    

    相关文章

      网友评论

          本文标题:Spring Boot 两种 AOP 拦截方式

          本文链接:https://www.haomeiwen.com/subject/bxtgyqtx.html