zoukankan      html  css  js  c++  java
  • Spring Boot 整合 AOP

    一、示例

    1、依赖

     1 <dependency>
     2             <groupId>org.springframework.boot</groupId>
     3             <artifactId>spring-boot-starter-web</artifactId>
     4         </dependency>
     5         <dependency>
     6             <groupId>org.springframework.boot</groupId>
     7             <artifactId>spring-boot-starter-aop</artifactId>
     8         </dependency>
     9         <dependency>
    10             <groupId>org.aspectj</groupId>
    11             <artifactId>aspectjrt</artifactId>
    12         </dependency>
    13         <dependency>
    14             <groupId>org.aspectj</groupId>
    15             <artifactId>aspectjweaver</artifactId>
    16         </dependency>
    17         <dependency>
    18             <groupId>cglib</groupId>
    19             <artifactId>cglib</artifactId>
    20             <version>2.2.2</version>
    21         </dependency>
    22         <dependency>
    23             <groupId>org.springframework</groupId>
    24             <artifactId>spring-aop</artifactId>
    25         </dependency>
    View Code

    2、Controller

     1 package com.aop.aop.controller;
     2 
     3 import org.springframework.web.bind.annotation.RequestMapping;
     4 import org.springframework.web.bind.annotation.RequestMethod;
     5 import org.springframework.web.bind.annotation.RestController;
     6 
     7 @RestController
     8 @RequestMapping("/aopController")
     9 public class AopController {
    10 
    11     @RequestMapping(value="/sayHello", method=RequestMethod.GET)
    12     public String sayHello(String name){
    13         return "hello" + name;
    14     }
    15 
    16     @RequestMapping(value="/sayHello2", method=RequestMethod.GET)
    17     public String sayHello2(String name){
    18         return "hello" + name;
    19     }
    20 }
    View Code

    3、定义切面类

     1 package com.aop.aop;
     2 
     3 import org.aspectj.lang.JoinPoint;
     4 import org.aspectj.lang.annotation.AfterReturning;
     5 import org.aspectj.lang.annotation.Aspect;
     6 import org.aspectj.lang.annotation.Before;
     7 import org.aspectj.lang.annotation.Pointcut;
     8 import org.slf4j.Logger;
     9 import org.slf4j.LoggerFactory;
    10 import org.springframework.stereotype.Component;
    11 import org.springframework.web.context.request.RequestContextHolder;
    12 import org.springframework.web.context.request.ServletRequestAttributes;
    13 
    14 import javax.servlet.http.HttpServletRequest;
    15 import java.util.Arrays;
    16 
    17 @Aspect
    18 @Component
    19 public class WebLogAcpect {
    20     private Logger logger = LoggerFactory.getLogger(WebLogAcpect.class);
    21 
    22     /**
    23      * 定义切入点,切入点为com.aop.aop.controller下的所有函数
    24      */
    25     @Pointcut("execution(public * com.aop.aop.controller..*.*(..))")
    26     public void webLog(){}
    27 
    28     /**
    29      * 前置通知:在连接点之前执行的通知
    30      * @param joinPoint
    31      * @throws Throwable
    32      */
    33     @Before("webLog()")
    34     public void doBefore(JoinPoint joinPoint) throws Throwable {
    35         // 接收到请求,记录请求内容
    36         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    37         HttpServletRequest request = attributes.getRequest();
    38 
    39         // 记录下请求内容
    40         logger.info("URL : " + request.getRequestURL().toString());
    41         logger.info("HTTP_METHOD : " + request.getMethod());
    42         logger.info("IP : " + request.getRemoteAddr());
    43         logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
    44         logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    45     }
    46 
    47     @AfterReturning(returning = "ret",pointcut = "webLog()")
    48     public void doAfterReturning(Object ret) throws Throwable {
    49         // 处理完请求,返回内容
    50         logger.info("RESPONSE : " + ret);
    51     }
    52 }
    View Code

    执行

    小结:

    1) 在完成引入AOP依赖包之后,一般并不需要去做其他配置,在AOP的默认配置属性中,spring.aop.auto属性默认是开启的,也就是说引入AOP依赖后,默认已经增加了@EnableAspectJAutoProxy。

    2) 定义切面类需要两个类的注解:@Component注解把切面类加入到IOC容器中;@Aspect注解使之成为切面类。

    3) 切面类中:@Pointcut定义切入点;

           @Before在连接点之前执行;

           @After:当某连接点退出时执行的通知(不论是正常返回还是异常退出)。;

                     @AfterReturning记录返回的对象;@AfterThrowing:在方法抛出异常退出时执行的通知。

        

    二、总结

    切点标志符号:

    AspectJ5的切点表达式由标志符和操作参数组成,如“execution(public * com.aop.aop.controller..*.*(..))“的切点表达式,execution就是标志符号,而圆括号里的“public * com.aop.aop.controller..*.*(..)”就是操作参数。

    execution

    匹配 join point 的执行, 例如 "execution(* hello(..))" 表示匹配所有目标类中的 hello() 方法. 这个是最基本的 pointcut 标志符.

    within

    匹配特定包下的所有 join point, 例如 within(com.xys.*) 表示 com.xys 包中的所有连接点, 即包中的所有类的所有方法. 而 within(com.xys.service.*Service) 表示在 com.xys.service 包中所有以 Service 结尾的类的所有的连接点.

    this 与 target

    this 的作用是匹配一个 bean, 这个 bean(Spring AOP proxy) 是一个给定类型的实例(instance of). 而 target 匹配的是一个目标对象(target object, 即需要织入 advice 的原始的类), 此对象是一个给定类型的实例(instance of).

    bean

    匹配 bean 名字为指定值的 bean 下的所有方法, 例如:

    bean(*Service) // 匹配名字后缀为 Service 的 bean 下的所有方法
    bean(myService) // 匹配名字为 myService 的 bean 下的所有方法
    args

    匹配参数满足要求的的方法.
    例如:

    @Pointcut("within(com.xys.demo2.*)")
    public void pointcut2() {
    }
    
    @Before(value = "pointcut2()  &&  args(name)")
    public void doSomething(String name) {
        logger.info("---page: {}---", name);
    }
    @Service
    public class NormalService {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        public void someMethod() {
            logger.info("---NormalService: someMethod invoked---");
        }
    
    
        public String test(String name) {
            logger.info("---NormalService: test invoked---");
            return "服务一切正常";
        }
    }

    当 NormalService.test 执行时, 则 advice doSomething 就会执行, test 方法的参数 name 就会传递到 doSomething 中.

    常用例子:

    // 匹配只有一个参数 name 的方法
    @Before(value = "aspectMethod()  &&  args(name)")
    public void doSomething(String name) {
    }
    
    // 匹配第一个参数为 name 的方法
    @Before(value = "aspectMethod()  &&  args(name, ..)")
    public void doSomething(String name) {
    }
    
    // 匹配第二个参数为 name 的方法
    Before(value = "aspectMethod()  &&  args(*, name, ..)")
    public void doSomething(String name) {
    }
    @annotation

    匹配由指定注解所标注的方法, 例如:

    @Pointcut("@annotation(com.xys.demo1.AuthChecker)")
    public void pointcut() {
    }

    则匹配由注解 AuthChecker 所标注的方法.

    常见的切点表达式

    匹配方法签名
    // 匹配指定包中的所有的方法
    execution(* com.xys.service.*(..))
    
    // 匹配当前包中的指定类的所有方法
    execution(* UserService.*(..))
    
    // 匹配指定包中的所有 public 方法
    execution(public * com.xys.service.*(..))
    
    // 匹配指定包中的所有 public 方法, 并且返回值是 int 类型的方法
    execution(public int com.xys.service.*(..))
    
    // 匹配指定包中的所有 public 方法, 并且第一个参数是 String, 返回值是 int 类型的方法
    execution(public int com.xys.service.*(String name, ..))
    匹配类型签名
    // 匹配指定包中的所有的方法, 但不包括子包
    within(com.xys.service.*)
    
    // 匹配指定包中的所有的方法, 包括子包
    within(com.xys.service..*)
    
    // 匹配当前包中的指定类中的方法
    within(UserService)
    
    
    // 匹配一个接口的所有实现类中的实现的方法
    within(UserDao+)
    匹配 Bean 名字
    // 匹配以指定名字结尾的 Bean 中的所有方法
    bean(*Service)
    切点表达式组合
     
    // 匹配以 Service 或 ServiceImpl 结尾的 bean
    bean(*Service || *ServiceImpl)
    
    // 匹配名字以 Service 结尾, 并且在包 com.xys.service 中的 bean
    bean(*Service) && within(com.xys.service.*)

    三、来源

    https://segmentfault.com/a/1190000007469968

    https://www.cnblogs.com/lic309/p/4079194.html

    https://blog.csdn.net/lmb55/article/details/82470388

  • 相关阅读:
    [程序员代码面试指南]数组和矩阵问题-未排序正数数组中累加和为给定值的最长子数组长度
    [Mysql]知识点
    [SSM项目]一-Eclipse 搭建marven-web项目 hello world!
    [BZOJ2252]矩阵距离(BFS)
    [Spring实战笔记]4面向切面编程的Spring-代理
    [程序员代码面试指南]数组和矩阵问题-找到无序数组中最小的k个数(堆排序)
    [Java]刷题中的Java基础
    MySql的大小写问题
    MySql密码丢失
    MySql的rpm安装
  • 原文地址:https://www.cnblogs.com/natian-ws/p/10820764.html
Copyright © 2011-2022 走看看