Spring Boot custom annotations, AOP cut unified print out reference request logs

 

 

 

In fact, Patricia went out before an article on how to use AOP aspects unified print request log, why you would go out of one? Nothing to write?

Haha, of course not! The reason was the implementation is still flawed for the following reasons:

  1. It is not flexible enough, because the method is a method in all Controller is cut, that cut dead, if we do not want to print out an interface parameter log on the impossible;
  2. When Controller package level too deep, resulting in many interfaces cut package less;

Today, the main talk about how custom annotations manner, to achieve AOP in Spring Boot cut unified print out reference log. Little friends can collect a wave.

Ado, get to the point!

First, take a look at the log output cut effect

Prior to look at the implementation method, we look at the effect Zeyang log output section:

 

 

Can be seen from the figure, each for each request, start and end at a glance, and prints the following parameters:

  • URL: request interface address;
  • Description: Chinese interface description information;
  • HTTP Method: The method of the request is  POSTGETor  DELETE the like;
  • Class Method: Method path is requested: package name + method name;
  • IP: IP address of the requesting party;
  • Request Args: the request parameters, the output JSON format;
  • Response Args: in response to the reference output JSON format;
  • Time-Consuming: Request time-consuming, in order to estimate the performance index for each interface;

how about it? It looks pretty good effect? Then take a look at our step by step how to implement it?

Second, add AOP Maven relies

In the project  pom.xml file to add dependencies:

<!-- aop 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- 用于日志切面中,以 json 格式打印出入参 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> </dependency> 

Third, custom log notes

Let us customize a log notes, as follows:

 

 

  • ①: When using this annotation, we define when to run;
  • ②: Notes for what we define as acting on the method;
  • ③: annotation whether included in the JavaDoc;
  • ④: Notes named  WebLog;
  • ⑤: the definition of a property, the default is an empty string;

Source code is as follows:

package site.exception.springbootaopwebrequest.aspect;

import java.lang.annotation.*;

/**
 * @author 犬小哈 (微信号:小哈学Java)
 * @site www.exception.site * @date 2019/2/12 * @time 下午9:19 * @discription **/ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface WebLog { /** * 日志描述信息 * * @return */ String description() default ""; } 

Here, a complete custom annotation definition is complete.

Fourth, the configuration of AOP section

Before configuring AOP aspects, we need to understand the next  aspectj effects associated annotation:

  • @Aspect: declare the class as an annotation class;
  • @Pointcut: the definition of a cut point, followed by an expression, an expression can be defined as cut annotations, the method may also be cut at a certain Package;

After a good cut point is defined, it is the fuss around this cut-off point:

  • @Before: before the tangent point, woven into the relevant code;
  • @After: After the cut point, woven into the relevant code;
  • @AfterReturning: Content after returning at tangent point, woven into the relevant code, is generally used to do a return value processing scene;
  • @AfterThrowing: processing logic for processing when woven into the code throws an exception;
  • @Around: surround and to be woven into the code before and after the entry point, and can freely control when performing the cut point;

 

 

Next, define a  WebLogAspect.java section class, declare a cut point:

 

 

Then, define  @Around surrounded contact point for when to perform:

 

 

  • ①: the record about the start time of the call interface;
  • ②: performing tangent point, after performing the cut point will @Before order to call -> Interface logic code -> @After -> @AfterReturning;
  • ③: print out the parameters;
  • ④: print interface time-consuming process;
  • ⑤: Returns the interface returns a reference result;

Let's look at  @Before methods:

 

 

See description annotations, comments are right because it is quite clear!

Finally,  @After to be ending:

 

 

 

 

Finally, we print the log marks the end of each interface. Finally, look at the project package structure:

 

 

Here, the relevant section of the code is complete!

The complete code:

package site.exception.springbootaopwebrequest.aspect;

import com.google.gson.Gson;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; 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.lang.reflect.Method; /** * @author 犬小哈 (微信号:小哈学Java) * @site www.exception.site * @date 2019/2/12 * @time 下午9:19 * @discription **/ @Aspect @Component @Profile({"dev", "test"}) public class WebLogAspect { private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class); /** 换行符 */ private static final String LINE_SEPARATOR = System.lineSeparator(); /** 以自定义 @WebLog 注解为切点 */ @Pointcut("@annotation(site.exception.springbootaopwebrequest.aspect.WebLog)") public void webLog() {} /** * 在切点之前织入 * @param joinPoint * @throws Throwable */ @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 开始打印请求日志 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 获取 @WebLog 注解的描述信息 String methodDescription = getAspectLogDescription(joinPoint); // 打印请求相关参数 logger.info("========================================== Start =========================================="); // 打印请求 url logger.info("URL : {}", request.getRequestURL().toString()); // 打印描述信息 logger.info("Description : {}", methodDescription); // 打印 Http method logger.info("HTTP Method : {}", request.getMethod()); // 打印调用 controller 的全路径以及执行方法 logger.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); // 打印请求的 IP logger.info("IP : {}", request.getRemoteAddr()); // 打印请求入参 logger.info("Request Args : {}", new Gson().toJson(joinPoint.getArgs())); } /** * 在切点之后织入 * @throws Throwable */ @After("webLog()") public void doAfter() throws Throwable { // 接口结束后换行,方便分割查看 logger.info("=========================================== End ===========================================" + LINE_SEPARATOR); } /** * 环绕 * @param proceedingJoinPoint * @return * @throws Throwable */ @Around("webLog()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = proceedingJoinPoint.proceed(); // 打印出参 logger.info("Response Args : {}", new Gson().toJson(result)); // 执行耗时 logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime); return result; } /** * 获取切面注解的描述 * * @param joinPoint 切点 * @return 描述信息 * @throws Exception */ public String getAspectLogDescription(JoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] methods = targetClass.getMethods(); StringBuilder description = new StringBuilder(""); for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { description.append(method.getAnnotation(WebLog.class).description()); break; } } } return description.toString(); } } 

Fifth, how to use it?

Because our cut-off point is a custom annotations  @WebLog, so we just need to add @WebLog in each controller Controller interface method can be annotated, if we do not want to print out an interface reference log, without comment on it:

 

 

Sixth, for file uploads Haoshi not?

Is crippled! Whether single-file uploads, or multi-file upload, cut logs are running well, stuff tested here, Patricia not posted out. Interested small partner can try!

Seven, want to use in development and test environments?

For those applications requiring high performance, do not want to print the log in a production environment, you want to use in a development environment or test environment, how to do it? We only need to add a section  @Profile on it, as shown below:

 

 

This specifies effect only on the  dev development environment and  test test environment, the production environment  prod is not in effect!

Eight multi-slice how to assign a priority?

Let's say our service is defined in more than one section, for example, we interfaces for the Web layer, more than you want to print the log, but also check token and so on. To specify how to cut the priority it? That is how to specify the section execution order?

We can  @Order(i)specify the annotation priority attention: the smaller the i value, the higher the priority.

Let's say we have defined above in this section of the log priority  @Order(10), then we have a check  token of the section  CheckTokenAspect.java, we define the order  @Order(11), the execution order between them is as follows:

 

 

We can summarize:

  • Prior to the cut point, @Order from small to large is performed, that is to say the smaller the higher the priority;
  • After the cut point, @Order the descending is performed, i.e. the greater the higher the priority;

Nine, Ref

http://blog.didispace.com/springbootaoplog

Ten, GitHub source address

https://github.com/weiwosuoai/spring-boot-tutorial/tree/master/spring-boot-aop-web-request

 

Reprinted: https://www.exception.site/springboot/spring-boot-aop-web-request

Guess you like

Origin www.cnblogs.com/Gent-Wang/p/11593316.html