1. Introduce Aop dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Copy the code

2. Define sectionsAspect

package com.example.boot.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * com.example.boot.aspect
 * Description:
 *
 * @author jack
 * @date2021/6/24 11:18am */
@Aspect
@Component
@Slf4j
public class LogAspect {

    /** * Configure pointcut */
    @Pointcut("@annotation(com.example.boot.aspect.Log)")
    public void logPointcut(a) {}/** * Configure surround notifications, using pointcuts ** registered with the method logPointcut()@param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        printLog(joinPoint, startTime);
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        log.debug("Cost : {}ms", endTime - startTime);
        System.out.println();
        return result;
    }

    private void printLog(ProceedingJoinPoint joinPoint, long startTime) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (Objects.isNull(servletRequestAttributes)) {
            return;
        }
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        String requestType = request.getMethod();
        String uri = request.getRequestURI();
        String requestTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date(startTime));
        log.debug("====================Request time:{}====================", requestTime);
        log.debug("Controller : {}#{}", className, methodName);
        log.debug("RequestType : {}", requestType);
        log.debug("Uri : {}", uri);
        log.debug("Parameters : {}", geParametersString(request));
        log.debug("RequestJson : {}", getSubscribeJson(request));
        log.debug("Ip : {}", getIpAddress(request));
    }

    /** * Get the form submission parameters **@param request requestp
     * @return parameterString
     */
    private String geParametersString(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringBuilder stringBuilder = new StringBuilder();
        parameterMap.forEach((k, v) -> stringBuilder.append(k).append("=").append(Arrays.toString(v)).append(""));
        return stringBuilder.toString();
    }

    /** * Get json ** from request@param request request
     * @return parameterJson
     */
    public String getSubscribeJson(HttpServletRequest request) {
        String contentType = request.getContentType();
        if (!"application/json".equals(contentType)) {
            return null;
        }
        BufferedReader reader = null;
        StringBuilder stringBuilder = new StringBuilder();
        try {
            reader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
            String line;
            while((line = reader.readLine()) ! =null) { stringBuilder.append(line); }}catch (IOException e) {
            log.error("Failed to get JSON data from request");
        } finally {
            try {
                if (null != reader) {
                    reader.close();
                }
            } catch (IOException e) {
                log.error("GetSubscribeJson () failed to close the data stream"); }}return stringBuilder.toString();
    }

    /** * Obtain client IP **@param request request
     * @return ip
     */
    private String getIpAddress(HttpServletRequest request) {
        String unknown = "unknown";
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        returnip; }}Copy the code

3. Customize annotations to intercept sections

/**
 * com.example.boot.aspect
 * Description:
 *
 * @author jack
 * @date 2021/6/24 11:20 上午
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
}
Copy the code

4. Use annotations

@RestController
@RequestMapping(value = "/message")
@Slf4j
public class MessageController {

    @Log
    @GetMapping(value = "/getOne")
    public void getOne(Long id) {
        log.info("getOne:{}", id); }}Copy the code

Effect of 5.

6.adviceOrder of execution

6.1 Order of normal cases of a single section

  1. @Around
  2. @Before
  3. joinPoint.proceed();Execution method
  4. @AfterReturning
  5. @After
  6. @Around

6.2 Sequence of single section exceptions

  1. @Around
  2. @Before
  3. joinPoint.proceed();Execution method
  4. @AfterThrowing

6.3 Sequence of normal cases of multiple sections

The smaller the @order value, the more the Order is executed first, and the more the Order is executed last

  1. Aspect1 @Around
  2. Aspect1 @Before
  3. Aspect2 @Around
  4. Aspect2 @Before
  5. Aspect2 joinPoint.proceed();Execution method
  6. Aspect2 @AfterReturning
  7. Aspect2 @After
  8. Aspect2 @Around
  9. Aspect1 @AfterReturning
  10. Aspect1 @After
  11. Aspect1 @Around

6.4 Test Code

LogAspect1

package com.example.boot.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * com.example.boot.aspect
 * Description:
 *
 * @author jack
 * @date2021/6/24 11:18am */
@Aspect
@Component
@Slf4j
@Order(1)
public class LogAspect1 {

    /** * Configure pointcut */
    @Pointcut("@annotation(com.example.boot.aspect.Log)")
    public void logPointcut(a) {}/** * Notice before declaration **@param point point
     */
    @Before("logPointcut()")
    public void doBefore(JoinPoint point) {
        log.info("LogAspect1:doBefore");
    }

    /** * Notice after declaration **@param point       point
     * @param returnValue returnValue
     */
    @AfterReturning(pointcut = "logPointcut()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point, Object returnValue) {
        log.info("LogAspect1:doAfterReturning,returnValue:{}", returnValue);
    }

    /** * Declare exception notification **@param e e
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        log.error("LogAspect1:doAfterThrowing", e);
    }

    /** * Declaration final Notice */
    @After("logPointcut()")
    public void doAfter(a) {
        log.info("LogAspect1:doAfter");
    }

    /** * Configure surround notifications, using pointcuts ** registered with the method logPointcut()@param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("LogAspect1:doAround-1");
        Object result = joinPoint.proceed();
        log.info("LogAspect1:doAround-2");
        returnresult; }}Copy the code

LogAspect2

package com.example.boot.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * com.example.boot.aspect
 * Description:
 *
 * @author jack
 * @date2021/6/24 11:18am */
@Aspect
@Component
@Slf4j
@Order(2)
public class LogAspect2 {

    /** * Configure pointcut */
    @Pointcut("@annotation(com.example.boot.aspect.Log)")
    public void logPointcut(a) {}/** * Notice before declaration **@param point point
     */
    @Before("logPointcut()")
    public void doBefore(JoinPoint point) {
        log.info("LogAspect2:doBefore");
    }

    /** * Notice after declaration **@param point       point
     * @param returnValue returnValue
     */
    @AfterReturning(pointcut = "logPointcut()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point, Object returnValue) {
        log.info("LogAspect2:doAfterReturning,returnValue:{}", returnValue);
    }

    /** * Declare exception notification **@param e e
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        log.error("LogAspect2:doAfterThrowing", e);
    }

    /** * Declaration final Notice */
    @After("logPointcut()")
    public void doAfter(a) {
        log.info("LogAspect2:doAfter");
    }

    /** * Configure surround notifications, using pointcuts ** registered with the method logPointcut()@param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("LogAspect2:doAround-1");
        Object result = joinPoint.proceed();
        log.info("LogAspect2:doAround-2");
        returnresult; }}Copy the code