Spring Boot 2.x:AOP Reality--Print Interface Log

What does interface log do

In our daily development process, we can view some details of this interface through the interface log.For example, the IP of the client, the type of client, the response time, the type of request, the interface method of the request and so on, we can make statistical analysis on these data to extract the information we want.

How to get the interface log

Here, we use the AOP of Spring's two killers, define a tangent point at the Controller layer, then analyze the requesting object to get interface information, and open a ThreadLocal to record response time.

Notes on AOP

  • @Aspect: Defines a class as a tangent class.
  • @Pointcut: Define a starting point.
  • @Before: Cut in at the beginning of the entry point.
  • @After: Cut in at the end of the entry point.
  • @AfterReturning: Entering content after the entry point returns content (which can be used to do some processing on processing the return value).
  • @Around: Cut in before and after the entry point and control when to execute the entry point's own content
  • @AfterThrowing: Used to handle handling logic after an exception is thrown in the cut-in content section.
  • @Order: Operations before the entry point are performed from small to large by order value; operations after the entry point are performed from large to small by order value.

Practical application

One: Introducing dependency

First, we need to add a dependency that introduces aop, a UserAgentUtils package for analyzing client information, and a Lombook package for @Slf4j print logs:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>eu.bitwalker</groupId>
            <artifactId>UserAgentUtils</artifactId>
            <version>1.20</version>
        </dependency>

Two: Define a ResponseAop tangent class

This class has already been defined in the previous Unified Return Values and Exception Handling and is improved here.Let me rewrite the code here:

@Aspect
@Order(5)
@Component
@Slf4j
public class ResponseAop

Three: Define a ThreadLocal variable

Defining the base type directly here has synchronization problems, so we define a ThreadLocal object to record the time consumed.

ThreadLocal<Long> startTime = new ThreadLocal<>();

Four: Define the point of tangency

The point of tangency should be written correctly to ensure that AOP works!Here are some simple writings, followed by a separate chapter on execution expression writing.

  • Any public method:

execution(public * *(..))

  • Execution of any method starting with "set":

execution(* set*(..))

  • Execution of any method of the Service interface:

execution(* com.xyz.service.Service.*(..))

  • Execution of any method defined in the service package:

execution(* com.xyz.service.*.*(..))

  • Execution of any method that defines any class in the service package and all subpackages:

execution(* com.xyz.service..*.*(..))

    /**
     * Tangent Point
     */
    @Pointcut("execution(public * indi.viyoung.viboot.*.controller..*(..))")
    public void httpResponse() {
    }

Five: Get request information in @Before

@Before("httpResponse()")
    public void doBefore(JoinPoint joinPoint){
        //Start Timing
        startTime.set(System.currentTimeMillis());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //Print the requested content
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));//Get User-Agent in Request Header
        log.info("Interface Path:{}" , request.getRequestURL().toString());
        log.info("Browser:{}", userAgent.getBrowser().toString());
        log.info("Browser version:{}",userAgent.getBrowserVersion());
        log.info("operating system: {}", userAgent.getOperatingSystem().toString());
        log.info("IP : {}" , request.getRemoteAddr());
        log.info("Request type:{}", request.getMethod());
        log.info("Class method : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("Request parameters : {} " + Arrays.toString(joinPoint.getArgs()));
    }

Six: Get the return value and execution time of the method in @AfterReturning

    @AfterReturning(returning = "ret" , pointcut = "httpResponse()")
    public void doAfterReturning(Object ret){
        //Return content after processing the request
        log.info("Method return value:{}" , ret);
        log.info("Method execution time:{}Millisecond", (System.currentTimeMillis() - startTime.get()));
    }

Seven: Test results

Next, we access an interface:

2019-02-21 21:03:31.358  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Interface Path: http://localhost:8090/users
2019-02-21 21:03:31.359  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Browser: CHROME
2019-02-21 21:03:31.359  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Browser version: 72.0.3626.109
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : operating system: MAC_OS_X
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : IP : 0:0:0:0:0:0:0:1
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Request type: GET
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Class method : indi.viyoung.viboot.apilog.controller.UserController.findAll
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Request parameters : {} []
...
2019-02-21 21:03:31.393  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Method return value: ReturnVO{code='2000', message='Operation Successful', data=[User(id=10000001, password=123456, userName=vi-young), User(id=10000002, password=123456, userName=vi-young), User(id=10000003, password=123123, userName=lxt), User(id=10000004, password=123456, userName=yangwei)]}
2019-02-21 21:03:31.393  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : Method execution time: 36ms

As you can see, we've got the information we want~

In future applications, we will save this information in the database and use some data analysis tools for analysis.

Public Number

Your recommendation is of great help to me!

Keywords: Java Spring Database

Added by Anthony1312002 on Tue, 06 Aug 2019 05:27:26 +0300