In this point

  • Briefly review SpringAOP: key terms, advice types, pointcut expressions, and so on.
  • SpringBoot is introduced to quickly start testing AOP and cleverly print log information.

Briefly review SpringAOP related knowledge points

SpringAOP related knowledge points include source code parsing, in order to deepen the impression, here again do a brief review:

1. AOP key terms

  • Aspect: This is the module that we define to focus on providing ancillary functions, such as security management, logging information, etc.
  • Join points: join points are where the aspect code can access normal business. Each point of each method in the diagram is a JoinPoint.
  • PointCut: An aspect does not need to inform all join points. Instead, it adds rules for cutting on top of join points, selects points that need to be enhanced, and finally the pointcuts that are really informed are the pointcuts.
  • Advice: The work that needs to be done. There are five types of Advice: before, after, afterReturning, afterThrowing, and around.
  • Weaving: the process of applying aspects to a target object and creating proxy objects. SpringAOP chooses to dynamically create proxy pairs during the run time of the target object
  • Introduction: An introduction can dynamically add methods or fields to a class at run time without modifying the code.

2. Five types of notification

  • Pre-notification Before: Notification executed Before the target method invocation.
  • Post-notification After: notification that will be executed anyway After the target method completes.
  • Returns notification AfterReturning: notification that is invoked after the target method succeeds.
  • AfterThrowing: Notifications that are called after the target method throws an exception.
  • Circular notification Around: Can be considered a combination of the previous four.

Pointcut expressions

As mentioned above, adding entry rules to join points is equivalent to defining pointcuts. Of course, there are many kinds of pointcut expressions. Here we will mainly study execution and annotation expressions.

execution

  • Return the package name of the value. The package name… Class name. Method name (parameter list)
  • Example: the execution (public void com. Smday. Service. The impl. AccountServiceImpl. SaveAccount ())
  • Access modifiers can be omitted and return values can be matched using the wildcard *.
  • Package names can also be matched with *, the number represents the hierarchy of packages, and the current package can use.. Flags, such as * *.. AccountServiceImpl.saveAccount()
  • Both class and method names can also be matched with * : * *.. *. * ()
  • Parameter lists use.. It can be identified with or without parameters, and the parameters can be of any type.

Full wildcard writing: * *… *. * (…).

Typically, pointcuts should set all methods under the business layer implementation class: * com.smday.service.impl.*.*(..) .

@annotation

The method that matches the Annotation Annotation whose join point is specified by its argument. That is, all methods specified for annotation annotation will match.

@annotation(com.hyh.annotation.log) : Specifies the join point of the Log annotation method.

4. AOP application scenarios

  • log
  • Monitor performance
  • Access control
  • Transaction management

Quick start

Introduction of depend on

If you’re using SpringBoot, you just need to introduce spring-boot-starter-AOP. The framework already incorporates Spring-AOP with AspectJWeaver.

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

Define log information encapsulation

/** * @author Summerday */ @data @toString public class WebLog implements Serializable {private static final long serialVersionUID = 1L; // Operation description private String description; Private Long startTime; Private Integer timeCost; // URL private String url; // URI private String uri; // Request type private String httpMethod; // IP address private String ipAddress; Private Object params; Private Object result; // Operation type private String methodType; }Copy the code

Custom annotation @log

@Target({ElementType.PARAMETER,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface /** * description */ String description() default ""; /** * MethodType INSERT DELETE UPDATE OTHER */ MethodType MethodType () default methodtype.other; }Copy the code

Defining the test interface

@RestController public class HelloController { @PostMapping("/hello") @Log(description = "hello post",methodType = MethodType.INSERT) public String hello(@RequestBody User user) { return "hello"; } @GetMapping("/hello") @Log(description = "hello get") public String hello(@RequestParam("name") String username, String hobby) { int a = 1 / 0; return "hello"; }}Copy the code

Define the Aspect and Pointcut

Use @aspect annotations to identify aspects and @pointcut to define pointcuts.

@author Summerday */ @aspect @Component public class LogAspect {private static final Logger log = LoggerFactory.getLogger(LogAspect.class); / tangent point * * * * web layer (1) the @pointcut (" execution (public * com. Hyh. Web. *. * (..) @pointcut ("@annotation(com.hyh.annotation.log)") Log annotation annotation method */ @Pointcut("@annotation(com.hyh.annotation.Log)") public void webLog() { } }Copy the code

Define the Advice method

I’m using wrap notification here,

@author Summerday */ @aspect @Component public class LogAspect {private static final Logger log = LoggerFactory.getLogger(LogAspect.class); / tangent point * * * * web layer (1) the @pointcut (" execution (public * com. Hyh. Web. *. * (..) @pointcut ("@annotation(com.hyh.annotation.log)") Log annotation annotation method */ @pointcut ("@annotation(com.hyh.annotation.log)") public void webLog() {} /** ** surround notification */ @around ("webLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {// Obtain the request Object HttpServletRequest Request = getRequest(); WebLog webLog = new WebLog(); Object result = null; Try {log. The info (" = = = = = = = = = = = = = = = = = pre notice = = = = = = = = = = = = = = = = = = = = = "); long start = System.currentTimeMillis(); result = joinPoint.proceed(); Log. The info (" = = = = = = = = = = = = = = = = = return notice = = = = = = = = = = = = = = = = = = = = = "); long timeCost = System.currentTimeMillis() - start; Log logAnnotation = getAnnotation(joinPoint); // Encapsulate webLog object weblog.setmethodType (logannotation.methodType ().name()); webLog.setDescription(logAnnotation.description()); webLog.setTimeCost((int) timeCost); webLog.setStartTime(start); webLog.setIpAddress(request.getRemoteAddr()); webLog.setHttpMethod(request.getMethod()); webLog.setParams(getParams(joinPoint)); webLog.setResult(result); webLog.setUri(request.getRequestURI()); webLog.setUrl(request.getRequestURL().toString()); log.info("{}", JSONUtil.parse(webLog)); } the catch (Throwable e) {the info (" = = = = = = = = = = = = = = = = = = abnormal notice = = = = = = = = = = = = = = = = = = = = = "); log.error(e.getMessage()); throw new Throwable(e); } the finally {log. The info (" = = = = = = = = = = = = = = = = = rear notice = = = = = = = = = = = = = = = = = = = = = "); } return result; } private Log getAnnotation(ProceedingJoinPoint joinPoint) {Method Method = ((MethodSignature)) joinPoint.getSignature()).getMethod(); return method.getAnnotation(Log.class); Params :{"name":" name"} */ private Object getParams(ProceedingJoinPoint joinPoint) { paramNames = getMethodSignature(joinPoint).getParameterNames(); // Parameter Values Object[] paramValues = joinPoint.getargs (); Map<String, Object> params = new LinkedHashMap<>(); for (int i = 0; i < paramNames.length; i++) { Object value = paramValues[i]; If (value instanceof MultipartFile) {MultipartFile file = (MultipartFile) value; value = file.getOriginalFilename(); } params.put(paramNames[i], value); } return params; } private MethodSignature getMethodSignature(ProceedingJoinPoint joinPoint) { return (MethodSignature) joinPoint.getSignature(); } private HttpServletRequest getRequest() { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); return requestAttributes.getRequest(); }}Copy the code

There are many different ways to handle weblogs. For performance reasons, you can store them in the database asynchronously, and the corresponding code has been uploaded to Gitee.

test

POST the content-type: http://localhost:8081/hello application/json {" id ": 1," username ":" day Joe pacha ", "age" : 18}Copy the code

The results are as follows:

= = = = = = = = = = = = = = = = = pre notice = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = return notice = = = = = = = = = = = = = = = = = = = = = {" ipAddress ":" 127.0.0.1 ", "description" : "hello Post ", "httpMethod" : "post", "params" : {" user ": {" id" : 1, "age" : 18, "username" : "day Joe pacha"}}, "uri" : "/ hello", "url" : "http://localhost:8 081/hello","result":"hello","methodType":"INSERT","startTime":1605596028383,"timeCost":28} ================= Post notification =====================Copy the code

Three things to watch ❤️

If you find this article helpful, I’d like to invite you to do three small favors for me:

  1. Like, forward, have your “like and comment”, is the motivation of my creation.

  2. Follow the public account “Java rotten pigskin” and share original knowledge from time to time.

  3. Also look forward to the follow-up article ing🚀

  4. [666] Scan the code to obtain the learning materials package