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

  • 相关阅读:
    [转]SVN服务器搭建和使用(二)
    [转]SVN服务器搭建和使用(一)
    BZOJ 2049 Sdoi2008 Cave 洞穴勘测
    BZOJ 1589 Usaco2008 Dec Trick or Treat on the Farm 采集糖果
    BZOJ 2796 POI2012 Fibonacci Representation
    BZOJ 2115 Wc2011 Xor
    BZOJ 3105 CQOI2013 新Nim游戏
    BZOJ 2460 Beijing2011 元素
    BZOJ 3687 简单题
    BZOJ 1068 SCOI2008 压缩
  • 原文地址:https://www.cnblogs.com/natian-ws/p/10820764.html
Copyright © 2011-2022 走看看