Global log printing / statistics interface for AOP aspect oriented programming

Posted by sonny on Sat, 29 Jan 2022 13:26:08 +0100

catalogue

1, What is AOP

2, AOP usage scenarios

3, Benefits of using AOP

4, Let's take an example to understand AOP aspect oriented programming

5, Spring 5 The AOP pointcut expression of X can be written in these ways

6, In practice, AOP based on Spring can quickly realize general log printing

7, In practice, it takes time to quickly implement the statistical interface of AOP based on Spring

This paper focuses on AOP aspect oriented programming. At the same time, in the actual project, user-defined annotation post notification and surround notification are used to realize the functions of unified log collection and interface time-consuming statistics respectively.

1, What is AOP

Aspect Oriented Program is aspect oriented programming. In other words, it adds additional functions without changing the original logic, such as solving system level problems or adding new functions


2, AOP usage scenarios

Permission control, caching, log processing, transaction control and interface statistics
AOP thought divides the function into two parts and separates various concerns in the system
Core concerns
Main functions of the business. For example, the order placing operation in the order module is the main function of the business
Crosscutting concerns
Non core, additional functions. For example, in the order module, the authority verification before the order operation, transaction control or anti resubmission verification, etc


3, Benefits of using AOP

Reduce code intrusion and decouple
Crosscutting logic can be handled uniformly
Easy to add and delete crosscutting logic


4, Let's take an example to understand AOP aspect oriented programming

User order logic
Core focus: creating orders
Crosscutting concerns: logging, controlling transactions, and permission verification

VideoOrderService{
    //New order
    addOrder(){ }
    //Query order
   findOrderById(){}
   //Delete order
   delOrder(){}
   //Update order
   updateOrder(){}   
}
JointPoint Connection point: addOrder/findOrderById/delOrder/updateOrder
Pointcut breakthrough point:Filter out those JointPoint Which objective functions are used to cut in, such as logging, which are usually added, deleted or modified
 You need to record the log, and the query log can be ignored
Advice notice:For actions executed on the functions in the pointcut, such as logging and permission verification, annotations are added to the corresponding methods.
Aspect section:It is composed of pointcuts and notifications, and defines the pointcuts to which notifications are applied
Weaving Weave in:The process of applying the section code to the objective function

Core concepts:

Notify Advice
There are five kinds of notifications for enhanced processing performed on specific pointcuts
@ Before advance notice
Run before executing the target method
@ After post notification
After the target method runs
@ AfterReturning return notification
Run after the target method returns a normal value
@ AfterThrowing exception notification
Run after the target method has an exception
@ Around surround notification
Enhance the processing before and after the completion of the target method. Surround notification is the most important notification type, such as transaction and log. Note that the core of programming is a processingjoinpoint, which needs to be executed manually procced()
What are you doing? For example, you need to record logs, control transactions, write general modules in advance, and call them directly where needed
Connection pointjointpoint
Where notification is required, the business process needs to be inserted into the specific location of the section during operation,
Generally, before and after the method call, all methods can be connection points
It's just a concept, nothing special
Pointcut
Not all methods are connection points. Filter connection points through specific rules, that is, Pointcut. Select the methods you want
In the program, it is mainly reflected in writing pointcut expressions (through wildcard and regular expressions) to filter out a specific set of JointPoint connection points
Filter out the joinpoint where the corresponding Advice will occur
Facet Aspect
It is usually a class, which defines the pointcut + notification and where to define it; When and what to do
The notice advice indicates the time and what to do (pre, post, etc.)
The pointcut specifies where to do this
In web interface design, web layer - > gateway layer - > service layer - > data layer, each layer is also an aspect, objects and objects, methods and methods are all aspects
Target target
The target class, the real business logic, can add new functions to the link of the target class without the knowledge of the target class
Weaving
The process of applying a slice (a class) to the objective function is called weaving
AOP agent
For the object created by AOP framework, the agent is the reinforcement of the target object
AOP proxy in Spring can make JDK dynamic proxy or CGLIB proxy

 

Example of pseudo code of order authority verification / log business process:

//Target class VideoOrderService; Each method is a connection point,; The pointcut is a method of CUD type, and the method read by R is not used as the pointcut
//Full name of CRDU: create, retrieve, update and delete

VideoOrderService{
    //New order
    addOrder(){ }
    //Query order
   findOrderById(){}
   //Delete order
   delOrder(){}
   //Update order
   updateOrder(){}   
}


//Permission aspect class = pointcut + notification 
PermissionAspects{
  
  //Where does the pointcut define
    @Pointcut("execution(public int net.wnn.permission.service.VideoOrderService.*(..))")
  public void pointCut(){}
  
  
  //The before notification indicates a cut in before the execution of the target method and specifies which method to cut in before
  //When and what to do
  @Before("pointCut()")
  public void permissionCheck(){
    
    System.out.println("stay xxx Perform permission verification before");
  }
  ....
}

//Log facet class = pointcut + notification 
LogAspect{
  
  //Where does the pointcut define
    @Pointcut("execution(public int net.wnn.permission.service.VideoOrderService.*(..))")
  public void pointCut(){}
  
  
  //The after notification indicates to cut in after the target method is executed, and specifies which method to cut in before
  //When and what to do
  @After("pointCut()")
  public void logStart(){
    
    System.out.println("stay xxx Log after");
  }
  ....
}

5, Spring 5 The AOP pointcut expression of X can be written in these ways

Pointcut expressions are optional except for return types, method names and parameters (modifiers are basically omitted and not written)
Access modifier , return value type (required) , package and class , method (required)
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)  throws-pattern?) 
For example, the above:
@Pointcut("execution(public int net.wnn.permission.service.VideoOrderService.*(..))")
Where: *: match a single VideoOrderService with any number of characters* Represents any method under VideoOrderService
..: () matches a method that does not accept any parameters
    (..) Matches a method that accepts any number of parameters
(*) matches a method that accepts an argument of any type
(*, Integer) matches a method that accepts two parameters, where the first parameter is of any type and the second parameter must be of type Integer

Common examples:
Arbitrary public method
execution(public * *(..))

Any method whose name starts with "save"
execution(* save*(..))

Any method defined by VideoService interface (identification)
execution(* net.wnn.service.VideoService.*(..))

Any method defined in the service package (identification)
execution(* net.wnn.service.*.*(..))

Match the service package and all methods of all classes under the descendant package (identification)
execution(* net.wnn.service..*.*(..))

6, In practice, AOP based on Spring can quickly realize general log printing

The first step is to enable spring AOP annotation configuration

@Configuration
@ComponentScan("net.wnn")
@EnableAspectJAutoProxy  //spring supports aspect s
public class AnnotationAppConfig {

}

Step two

Configure pointcuts and notifications. Custom annotation type configuration

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OpLog {

    /**
     *
     * Operation module
     */
    String opModule();

    /**
     *
     * Operation type
     */
    String operType();

    /**
     *
     * pedagogical operation
     */
    String operDesc();
}
import lombok.extern.slf4j.Slf4j;
import net.wnn.model.OpLog;
import org.aspectj.lang.JoinPoint;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

//Be sure to add spring for scanning
@Component
//Tell spring that this is an aspect class that can define pointcuts and notifications
@Aspect
@Slf4j
public class LogAdvice {

    /**
     * First define a tangent point
     */
    @Pointcut("@annotation(net.wnn.model.OpLog)")
    public void printLog() {
    }

    @After("printLog()")
    public void after(JoinPoint joinPoint){
        try {
            //Get method name
            String methodName = joinPoint.getSignature().getName();
            //Get class name
            String className = joinPoint.getSignature().getDeclaringTypeName();
            System.out.println("Class name:"+className+" Method name:"+methodName);
            // Method for obtaining weaving in point through reflection mechanism from weaving in point of section
            MethodSignature signature =(MethodSignature) joinPoint.getSignature();
            // Get the method where the pointcut is located
            Method method =signature.getMethod();
            // Get operation
            OpLog opLog =method.getAnnotation(OpLog.class);
            log.info("Module name:[{}],type:[{}],Description information:[{}]",opLog.opModule(),opLog.operType(),opLog.operDesc());
            //Method of executing connection point
            try {
                ((ProceedingJoinPoint)joinPoint).proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();

        }
    }

}

The third step is to add comments on the request method

  /**
     * User login
     * @param request
     * @return
     */
    @PostMapping("login")
    @OpLog(opModule = "User module",operType = "Login operation",operDesc = "This method allows the user to log in")
    public JsonData login(@RequestBody AccountLoginRequest request){
        JsonData jsonData = accountService.login(request);
        return jsonData;
    }

postman request interface verification:

In daily development work, the unified collected requirements can be warehoused according to the actual log storage requirements.

7, In practice, it takes time to quickly implement the statistical interface of AOP based on Spring

The first step is to enable spring AOP annotation configuration

@Configuration
@ComponentScan("net.wnn")
@EnableAspectJAutoProxy  //spring supports aspect s
public class AnnotationAppConfig {

}

Step 2 configure the entry point

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
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;


//Be sure to add spring for scanning
@Component
//Tell spring that this is an aspect class that can define pointcuts and notifications
@Aspect
@Slf4j
public class LogAdvice {

    //The pointcut expression can also be written directly on the notification
    @Pointcut("execution(* net.wnn.service.impl.AccountServiceImpl.*(..))")
    public void aspect(){

    }

    @Around("aspect()")
    public void around(JoinPoint joinPoint){
        Object target = joinPoint.getTarget().getClass().getName();
        //Get parameters through joinPoint
        Object [] args = joinPoint.getArgs();
        log.info("caller :{} Call method:{} Call parameters:{}",target,joinPoint.getSignature(),args[0]);

        long start = System.currentTimeMillis();
        log.info("===========Before surround notification========");
        //Method of executing connection point
        try {
            ((ProceedingJoinPoint)joinPoint).proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        long end = System.currentTimeMillis();
        log.info("===========After surround notification========");

        log.info("Total time taken to call a method time = " + (end - start) +" ms");
    }


}

Console output:

In the actual development work, the warehousing statistics can be displayed according to the received methods and time-consuming.