Spring Cloud Spring Boot mybatis distributed microservice cloud architecture (forty-one) realizes the logging aspect of the web layer

The aspects of realizing AOP mainly include the following elements:

  • Use @Aspectannotations to define a java class as an aspect class
  • Use to @Pointcutdefine a pointcut, which can be a regular expression, such as all functions under a package in the following example, or an annotation, etc.
  • Cut content at different positions of the cut point as needed
  • Use @Beforeto cut content at the beginning of the pointcut
  • Use @Afterto cut content at the end of the pointcut
  • Use @AfterReturningto cut in the content after the return content of the pointcut (can be used to do some processing on the return value)
  • Use @Aroundcontentcutting before and after the pointcut and control when the content of the pointcut itself is executed
  • Use @AfterThrowingthe processing logic to handle when an exception is thrown from the content section
    • 
      @Aspect
      @Component
      public class WebLogAspect {
      
          private Logger logger = Logger.getLogger(getClass());
      
          @Pointcut("execution(public * com.didispace.web..*.*(..))")
          public void webLog(){}
      
          @Before("webLog()")
          public void doBefore(JoinPoint joinPoint) throws Throwable {
              // 接收到请求,记录请求内容
              ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
              HttpServletRequest request = attributes.getRequest();
      
              // 记录下请求内容
              logger.info("URL : " + request.getRequestURL().toString());
              logger.info("HTTP_METHOD : " + request.getMethod());
              logger.info("IP : " + request.getRemoteAddr());
              logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
              logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
      
          }
      
          @AfterReturning(returning = "ret", pointcut = "webLog()")
          public void doAfterReturning(Object ret) throws Throwable {
              // 处理完请求,返回内容
              logger.info("RESPONSE : " + ret);
          }
      
      }
      

      You can see the above example, the @Pointcutdefined entry point is com.didispace.weball functions under the package (the entry point for all request processing in the web layer), and then through the @Beforeimplementation, the log of the request content is recorded (this article only describes the process, and the content can be adjusted as needed) ), and finally @AfterReturningthe object returned by the logging request.

      http://localhost:8080/hello?name=didiThe following log output can be obtained by running the program and accessing:

      
      2016-05-19 13:42:13,156  INFO WebLogAspect:41 - URL : http://localhost:8080/hello
      2016-05-19 13:42:13,156  INFO WebLogAspect:42 - HTTP_METHOD : http://localhost:8080/hello
      2016-05-19 13:42:13,157  INFO WebLogAspect:43 - IP : 0:0:0:0:0:0:0:1
      2016-05-19 13:42:13,160  INFO WebLogAspect:44 - CLASS_METHOD : com.didispace.web.HelloController.hello
      2016-05-19 13:42:13,160  INFO WebLogAspect:45 - ARGS : [didi]
      2016-05-19 13:42:13,170  INFO WebLogAspect:52 - RESPONSE:Hello didi
      

      Optimization: Synchronization issues in AOP aspects

      In the WebLogAspect aspect, two independent functions, doBefore and doAfterReturning, are used to implement the pointcut header and the content executed after the pointcut returns. If we want to count the processing time of the request, we need to record the time at doBefore and pass it at doAfterReturning. The current time and the time recorded at the beginning are calculated to obtain the elapsed time for request processing.

      So can we define a member variable in the WebLogAspect aspect to access doBefore and doAfterReturning together? Will there be synchronization issues?

      Indeed, defining the base type directly here will have synchronization problems, so we can introduce the ThreadLocal object and record it like this:

      
      @Aspect
      @Component
      public class WebLogAspect {
      
          private Logger logger = Logger.getLogger(getClass());
      
          ThreadLocal<Long> startTime = new ThreadLocal<>();
      
          @Pointcut("execution(public * com.didispace.web..*.*(..))")
          public void webLog(){}
      
          @Before("webLog()")
          public void doBefore(JoinPoint joinPoint) throws Throwable {
              startTime.set(System.currentTimeMillis());
      
              // 省略日志记录内容
          }
      
          @AfterReturning(returning = "ret", pointcut = "webLog()")
          public void doAfterReturning(Object ret) throws Throwable {
              // 处理完请求,返回内容
              logger.info("RESPONSE : " + ret);
              logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
          }
      
      
      }
      

      Optimization: Prioritization of AOP Aspects

      Due to the implementation of AOP, the program is well decoupled, but it also brings some problems, such as: we may do multiple aspects to the Web layer, verify users, verify header information, etc. A problem with the processing order of the facets is encountered.

      Therefore, we need to define the priority of each aspect, and we need @Order(i)annotations to identify the priority of the aspect. The smaller the value of i, the higher the priority . Suppose we have another aspect that is CheckNameAspectused to verify that the name must be didi, we set @Order(10)it, and the WebLogAspect above is set to @Order(5), so the WebLogAspect has a higher priority, and the execution order is as follows:

    • The content that is executed @Beforefirst in the content, the content that executes later@Order(5)@Order(10)

    • The content that executes first in @Afterand , the content that executes later@AfterReturning@Order(10)@Order(5)
    • So we can sum it up like this:

    • The operation before the pointcut is executed according to the value of order from small to large
    • The operation after the pointcut is executed according to the value of order from large to small
    • source code

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325856458&siteId=291194637