Download this chapter source code

โค๏ธ The source of this chapter has been shared on github

What is AOP

  • AOP is also calledSection-oriented programming, designed to improve by allowing separation of crosscutting concernsmodular. The popular understanding is to encapsulate the logic code that has nothing to do with the business, but is called by the business module together, and form a section to make the original business more powerful, that isTo enhanceAnd,Reduce duplicate code.To reduceBetween modulesThe couplingTo facilitate later operation and maintenance

Static proxy and dynamic proxy difference

  • The key of AOP implementation lies in the AOP proxy automatically created by AOP framework. AOP proxy can be divided into static proxy and dynamic proxy
    • Static agentAn AOP proxy class is compiled using commands provided by the AOP framework, thus generating AOP proxy classes at compile timeCompile-time enhancement
    • A dynamic proxyAOP dynamic proxy classes are “temporarily” generated in memory at runtime with the help of JDK dynamic proxy, CGLIB, etc., hence the termRuntime enhancement

Cglib and JDK dynamic proxy

What are the differences between Cglib and JDK dynamic proxies?

  • Cglib dynamic proxy: useThe ASM frameworkThe class file generated by the proxy object class is loaded in and generated by modifying its bytecodeA subclassTo deal with
    • Generates a subclass of the specified class that overrides the methods and their enhancements, but because it is inherited, it is best that the class or method does not generate final, because final classes or methods cannot be inherited
  • JDK dynamic proxy: Generates one using interceptors (you must implement InvocationHandler) and reflectionThe agent interfaceIs handled by calling InvokeHandler before invoking the concrete method
    • JDK dynamic proxies can only be implementedinterfaceGenerates proxies for classes, not for classes

Cglib and JDK dynamic proxy usage scenarios

  • The target object generates the interface using JDK dynamic proxies by default
  • If the target object uses an interface, you can force the use of cglib(add < AOP: Aspectj-autoproxy proxyt-target-class=”true”/> in the Spring configuration)
  • If the target object does not implement an interface, you must use the Cglib library, which Spring willautomaticBetween JDK dynamic proxy and Cglibconversion

Additional is faster than the JDK

  • Underlying cglib is the ASM bytecode generation framework, but bytecode technology generates proxy classes, which were more efficient than using Java reflection prior to JDK 1.6
  • After JDK6, the JDK dynamic proxy is gradually optimized, and the efficiency is higher than that of Cglib proxy when the number of calls is relatively small
  • Cglib is only efficient when a lot of calls are made, but by 1.8 the JDK was more efficient than Cglib
  • Cglib cannot proxy methods that declare final because Cglib dynamically generates proxy objects, immutable classes modified by the final keyword can only be referenced and cannot be modified
The difference between CGLIB JDK dynamic proxy
The principle of dynamicGenerate a proxyA subclass.Subclasses overrideAll non-final methods of the class to be proxied. The method interception technique in the subclass intercepts all calls to the parent class’s methods, weaving into crosscutting logic that is better than Java’s reflection of JDK dynamic proxiesfast Dynamic proxies in the JDK are implemented through reflection class Proxies and the InvocationHandler callback interface, but all classes in the JDK do dynamic proxiesMust beTo implement ainterface, that is, only methods defined in the interface implemented by this class can be proxy, which has some limitations in practical programming and uses reflection efficiencyThe slower
Whether to provide subclass proxy is no
Whether to provide interface proxy Yes (do not use interface) Yes (must)

Additional combat

Rely on

I tested it directly in the Springboot project, spring-core with cglib dependencies

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

code

Method to delegate say:

/ * * *@Description: The class to be proxied@Author: jianweil
 * @date: better 2021/12/7 * /
public class HelloWorld {
    public String say(boolean say) throws Exception {
        System.out.println("Hello Student");
        if(! say) {throw new Exception("Wrong answer!);
        }
        return "That's right!; }}Copy the code

The test class:

package com.ljw.springbootaop.proxy.cglib;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/ * * *@Description: Test cGLIb *@Author: jianweil
 * @date: 2021/12/7 arieh * /
@Slf4j
public class Enhancer2Test {

    /** ** */
    private static void before(a) {
        log.info("before method invoke...");
    }
    /** ** after notification */
    private static void after(a) {
        log.info("after method invoke...");
    }
    /** * Exception notification */
    private static void exception(a) {
        log.info("exception method invoke...");
    }
    /** * notifies */ before the method returns
    private static void beforeReturning(a) {
        log.info("beforeReturning method invoke...");
    }

    public static void main(String[] args) throws Exception {
        HelloWorld hello = new HelloWorld();
        There are other callback methods, too. Here we test the MethodInterceptor callback: MethodInterceptor
        HelloWorld proxyHW = (HelloWorld) Enhancer.create(hello.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object result = null;
                try {
                    // Pre-notification
                    before();
                    result = method.invoke(hello, objects);
                    // post notification
                    after();
                } catch (Exception e) {
                    // Exception notification
                    exception();
                } finally {
                    // notification before method return
                    beforeReturning();
                }

                returnresult; }});//String result = proxyHW.say(true);
        String result = proxyHW.say(false); System.out.println(result); }}Copy the code
  • Create the proxy class using Enhancer
  • Here we use a MethodInterceptor callback: MethodInterceptor, and a few others that you’ll have time to explore
  • The proxied class cannot be the final class

test

  • String result = proxyhw. say(true) :
15:57:01758. [main] INFO com.ljw.springbootaop.proxy.cglib.Enhancer2Test - before method invoke...
Hello Student
15:57:01760. [main] INFO com.ljw.springbootaop.proxy.cglib.Enhancer2Test - after method invoke...
15:57:01760.[main] INFO com.ljw.springbootaop.proxy.cglib.Enhancer2Test - beforeReturning method invoke... That's right!Copy the code
  • String result = proxyhw.say (false) :
Connected to the target VM, address: '127.0.0.1:53976'.transport: 'socket'
15:55:42.136 [main] INFO com.ljw.springbootaop.proxy.cglib.Enhancer2Test - before method invoke...
Hello Student
15:55:42.139 [main] INFO com.ljw.springbootaop.proxy.cglib.Enhancer2Test - exception method invoke...
15:55:42.139 [main] INFO com.ljw.springbootaop.proxy.cglib.Enhancer2Test - beforeReturning method invoke...
null
Copy the code

JDK dynamic proxy deployment

Rely on

The JDK environment comes with the JAR packages required by the JDK dynamic proxy.

code

Interface class:

public interface Animal {
    void doWhat(boolean isDo) throws Exception;
}
Copy the code

Implementation class:

public class Cat implements Animal {
    @Override
    public void doWhat(boolean isDo) throws Exception {
        if(! isDo) { System.out.println("Cat only eats!");
            throw new Exception("Cat only eats.");
        } else {
            System.out.println("Cat can meow, meow, meow."); }}}Copy the code

Proxy implementation class:

package com.ljw.springbootaop.proxy.jdk;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/ * * *@Description: todo
 * @Author: jianweil
 * @date: 2021/12/7 16:06 * /
@Slf4j
public class AnimalInvacationHandler implements InvocationHandler {

    private final Animal animal;

    public AnimalInvacationHandler(Animal animal) {
        this.animal = animal;
    }

    /** * -proxy: proxy object, newProxyInstance return object * - method: called method * - args: method parameters */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
            // Pre-notification
            before();
            result = method.invoke(animal, args);
            // post notification
            after();
        } catch (Exception e) {
            // Exception notification
            exception();
        } finally {
            // notification before method return
            beforeReturning();
        }

        return result;

    }


    private void before(a) {
        log.info("before method invoke...");
    }

    private void after(a) {
        log.info("after method invoke...");
    }

    private void exception(a) {
        log.info("exception method invoke...");
    }

    private void beforeReturning(a) {
        log.info("beforeReturning method invoke..."); }}Copy the code

The test class:

/ * * *@Description: Test JDK dynamic proxy *@Author: jianweil
 * @date: 2021/12/7 16:08 * /
public class InvacationHandlerTest {
    public static void main(String[] args) throws Exception {
        Animal cat = new Cat();
        /** * interfaces: interfaces that the dynamic proxy class implements */
        Animal animal = (Animal) Proxy.newProxyInstance(cat.getClass().getClassLoader(), Cat.class.getInterfaces(), new AnimalInvacationHandler(cat));
        animal.doWhat(true);
        //animal.doWhat(false);}}Copy the code

test

  • animal.doWhat(true);
16:28:04105.[main] INFO com.ljw.springbootaop.proxy.jdk.AnimalInvacationHandler - before method invoke... Cat can meow, meow, meow16:28:04107. [main] INFO com.ljw.springbootaop.proxy.jdk.AnimalInvacationHandler - after method invoke...
16:28:04107. [main] INFO com.ljw.springbootaop.proxy.jdk.AnimalInvacationHandler - beforeReturning method invoke...
Copy the code
  • animal.doWhat(false);
16:28:36.455[main] INFO com.ljw.springbootaop.proxy.jdk.AnimalInvacationHandler - before method invoke... Cat only eats!16:28:36.457 [main] INFO com.ljw.springbootaop.proxy.jdk.AnimalInvacationHandler - exception method invoke...
16:28:36.457 [main] INFO com.ljw.springbootaop.proxy.jdk.AnimalInvacationHandler - beforeReturning method invoke...
Copy the code

Differences between Spring AOP and Aspectj

  • Spring AOP

    • Spring AOP is a dynamic proxy that generates target classes at run time through a proxy. By default, if an interface is used, JDK dynamic proxy is used. If no interface is used, CGLIB is used
    • Spring AOP aims to address the most common AOP (method weaving) in enterprise development, simplyMethod to weave
    • Spring AOP needDependent IOC containerCan only work with the Spring container and is implemented using pure Java code
    • In terms of performance, since Spring AOP is implemented based on dynamic proxies, the need to generate proxy instances when the container is started, and the depth of the stack in method calls makes Spring AOP’sPerformance isAspectJpoor
    • Spring AOPSupport for annotationsTo make it easier to create and configure aspects using the @Aspect annotation.
  • AspectJ

    • AspectJ is a static proxy that compiles aspect code to object code at compile time. This is done by modifying the code. There are several weaving opportunities:
      • Compile-time weaving: If class A adds an attribute using AspectJ and class B references it, the scenario needs to be compile-time weaving otherwise class B won’t Compile.
      • Post-compile weaving: that’s where the.class file is generated, or the weaving jar file is generated, and we need to improve the weaving.
      • Load-time weaving: Weaving occurs when classes are being loaded, and there are several common ways to do this.
        • 1. Custom class loaders do this, which is probably the easiest way to load classes before they are woven into the JVM, so you can define the behavior at load time.
        • Specify aspectJ-provided agent at JVM startup time:-javaagent:xxx/xxx/aspectjweaver.jar.
    • AspectJ can do things Spring AOP can’t; it is a complete solution to AOP programming that AspectJ supportsAll pointcutsAnd not just method weaving.
    • Because AspectJ does the weaving before it actually runs, the classes it generates areNo additional runtime overheadthe
    • You need to create the facets through an.AJ file, and you need to use ajC (Aspect compiler) to compile the code.
Spring AOP AspectJ
Implemented in pure Java Extended implementation using the Java programming language
No separate compilation process is required The AspectJ compiler (AJC) is required unless LTW is set up
Can only useThe runtimeweave Runtime weaving is not available. supportCompile time, compile time, and load timeweave
Not very functional – only supportedMethod levelweaving More powerful– You can weave fields, methods, constructors, static initializers, final classes/methods, etc.
It can only be implemented on beans managed by the Spring container This can be implemented on all domain objects
Only supportmethodsExecution pointcut supportAll pointcuts
Proxies are created by target objects, and facets are applied to them Aspects are woven directly into the code before the application is executed (at run time)
Than the AspectJslowMuch more betterThe performance of the
Easy to learn and apply It’s more complicated than Spring AOP

myth

  • Used to thinkAspectJ is part of Spring AOP because Spring AOP uses AspectJ’s annotations.
    • Aspects are used to define aspects, pointcuts are used to define pointcuts, and Advice is used to define enhanced processing.
  • Spring AOP uses Aspect annotations (@aspect, @pointcut, @before, etc.), but it doesn't use its compiler or weavers. It is implemented using JDK dynamic proxies and CGLIB, which generate proxy classes at run time.
  • To enable Spring’s support for the configuration of the @AspectJ aspect, and to ensure that target beans in the Spring container are automatically enhanced by one or more aspects, you must add the following configuration to the Spring configuration file: < AOP: Aspectj-autoproxy /> support is enabled by default in older versions of SpringBoot and does not need to be configured.

JDK dynamic proxy, Cglib, Spring AOP and Aspectj

  • Spring AOP and Aspectj are two frameworks that implement AOP
  • Spring AOP uses dynamic proxies
    • Dynamic proxies are implemented in two underlying technologies:
      • JDK dynamic proxies (target classes with default interfaces use JDK dynamic proxies)
      • Cglib (used by target classes with or without interfaces)
    • Spring AOP uses the annotations provided by the Aspectj package, but the underlying compiler and weaver are not Aspectj
  • Aspectj uses static proxies

6. AOP related concepts

Section (Aspect)

  • The section is oneModularity of crosscutting concerns, a facet can contain different enhancements of the same type. For example, transaction processing and logging can be understood as two facets.
  • Section byThe breakthrough pointandnoticeComponent, which contains both the definition of crosscutting logic and the definition of pointcuts.
  • Spring AOP is the framework responsible for implementing the aspect, weaving the crosscutting logic defined by the aspect into the join points specified by the aspect.
@Component
@Aspect
public class LogAspect {}Copy the code

Target Object

  • Target object means willThe enhanced objectThat is, the class object containing the main business logic. Or an object notified by one or more facets

JoinPoint

  • A specific point in the execution of a program, e.gMethod callOr a specific exception is thrown. Join points are determined by two pieces of information:
    • Method (indicates the program execution point, i.e. at which target method)
    • Relative point (indicates orientation, i.e. where the target method is located, e.g. before, after, etc.)
  • In a nutshell,Join points are the program execution points that are interceptedBecause of Spring AOPOnly join points of method types are supportedSo join points are methods that are intercepted in Spring.
@Before("pointcut()")
public void log(JoinPoint joinPoint) { // the JoinPoint argument is the JoinPoint
}
Copy the code

Point (PointCut)

  • Pointcuts are conditional definitions that intercept join points. How pointcut expressions match join points is at the heart of AOP, and Spring uses AspectJ pointcut syntax by default.
  • In general, all methods can be considered join points, but we do not want to add advice to all methods, andThe purpose of a pointcut is to provide a set of rules (described using AspectJ Pointcut Expression Language) to match join pointsTo add notifications to join points that meet the rule.
  1. The matching rules for pointcuts arecom.ljw.test.aop.serviceAll functions of all classes under the package.
@Pointcut("execution(* com.ljw.test.aop.service.. *. * (..) )"
public void Pointcut(a) {}
Copy the code

The entire expression can be divided into four parts:

  • The first * : indicates the return type, and the * indicates all types
  • Packet name: indicates the name of the packet to be intercepted, followed by.. Said the current bag and the bag of all child bag, com. LJW. Test. Aop. Children of service package, package of all classes of methods.
  • The second * : indicates the class name, and the * indicates all classes.
  • * (..) The final asterisk represents the method name, the asterisk represents all methods, the parenthesis represents method arguments, and the two periods represent any arguments
  1. All method facets for all classes in the com.ljw.controller package
 @Pointcut("execution(public * com.ljw.controller.*.*(..) )"
Copy the code
  1. For the UserController class section only
@Pointcut("execution(public * com.ljw.controller.UserController.*(..) )"
Copy the code
  1. Unified pointcuts for all method facets of all classes in com.ljw and its subpackages
@Pointcut("execution(* com.ljw.controller.*.*(..) )"
Copy the code

Notice (Advice)

  • Notification is after interception at the join pointThe code to execute, including around, before, and after types of notifications.
  • The Spring AOP framework implements the notification model with interceptors and maintains a chain of interceptors centered around join points.
JoinPoint = JoinPoint; // JoinPoint = JoinPoint; // JoinPoint = JoinPoint
@Before("pointcut()")
public void log(JoinPoint joinPoint) {}Copy the code

Weave (has)

  • Weaving is the process of connecting facets to business logic objects and creating a notification broker.
  • Weaving can be done at compile time, class load time, and run time.
  • Weaving at compile time is a static proxy, while weaving at run time is a dynamic proxy.

Enhancer (Advisor)

  • The Advisor is another implementation of the aspect, weaving the advice into the target object in a more complex way, and is an assembler that wraps the advice into a more complex aspect.
  • Advisors consist of pointcuts and Advice.
  • The concept of Advisor comes from Spring’s support for AOP and has no equivalent in AspectJ. The Advisor is like a small self-contained aspect that has only one notification. The aspect itself is represented by a Bean, and a default interface must be implemented.
// AbstractPointcutAdvisor is the default interface
public class LogAdvisor extends AbstractPointcutAdvisor {
 private Advice advice; // Advice
 private Pointcut pointcut; / / point

 @PostConstruct
 public void init(a) {
 / / AnnotationMatchingPointcut is according to modify the class and method annotations to intercept point.
 this.pointcut = new AnnotationMatchingPointcut((Class) null, Log.class);
 / / notice
 this.advice = newLogMethodInterceptor(); }}Copy the code

Seven, AOP common annotations

  • @aspect: Identifies the current class as an Aspect for the container to read
  • Pointcut: A Pointcut is the definition of a condition that intercepts join points, which in a program is primarily written as a Pointcut expression
  • @before: Identifies a front-enhanced method, equivalent to the BeforeAdvice functionality
  • AfterReturning: AfterReturning enhancement, equivalent to AfterReturningAdvice, executed when methods exit
  • AfterThrowing: Exception throw enhancement, equivalent to ThrowsAdvice
  • @after: Final enhancement, whether an exception is thrown or a normal exit
  • @around: Surround-enhanced, equivalent to MethodInterceptor

Eight, AOP execution order

Successful execution:

Graph LR Around --> Before Before --> Business Business --> AfterReturning AfterReturning --> After After --> Around

Execution failed (note that there is no Around) :

Graph LR Around Before --> Before --> Business business --> AfterThrowing AfterThrowing --> After

AOP practice: log collection

Demand analysis

  • Logging uses annotations to make business code less intrusive
  • Logs can be divided into modules
  • Logs record different operations
  • Logs record the IP addresses of operations
  • Logs need to be persisted to the database

Log notes

/ * * *@Description: Log annotations *@Author: jianweil
 * @date: 2021/12/6 and * /
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /** * module */
    String module(a) default "";

    /** * Action category */
    ActionType actionType(a) default ActionType.OTHER;

    /** * Operator type */
    OperatorType operatorType(a) default OperatorType.MANAGE;

    /** * Whether to save the request parameters */
    boolean saveParameter(a) default true;
}
Copy the code

The log section

/ * * *@Description: Operation log processing *@Author: jianweil
 * @date: 2021/12/6 my * /
 / / section
@Aspect
@Component
public class LogAspect {

    @Resource
    private ApplicationContext appContext;

    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    /** * Configure the pointcut */
    @Pointcut("@annotation(com.ljw.springbootaop.aspect.annotation.Log)")
    public void logPointCut(a) {}/** * notification: execute ** after processing the request@paramJoinPoint joinPoint */
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    /** * Notification: intercept abnormal operation **@paramJoinPoint connection point *@paramE * /
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
        try {
            // Get comments
            Log controllerLog = getAnnotationLog(joinPoint);
            if (controllerLog == null) {
                return;
            }

            // Get the current login user
            LoginUser loginUser = appContext.getBean(LoginUser.class);

            // *======== database log =========*//
            SysOperLog operLog = new SysOperLog();
            //ๆจกๆ‹Ÿid
            operLog.setOperId((long) new Random().nextInt());
            // Status 1 is successful
            operLog.setStatus(1);
            // The requested address
            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
            operLog.setOperIp(ip);
            // Return parameters
            operLog.setJsonResult(JSON.toJSONString(jsonResult));

            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());

            if(loginUser ! =null) {
                operLog.setOperName(loginUser.getUsername());
            }

            if(e ! =null) {
                operLog.setStatus(0);
                operLog.setErrorMsg(StrUtil.sub(e.getMessage(), 0.2000));
            }
            // Set method name
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            operLog.setMethod(className + "." + methodName + "()");
            // Set the request mode
            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
            // Handle setting the parameters on the annotations
            getControllerMethodDescription(joinPoint, controllerLog, operLog);
            // Save the database
            log.info("# # # # # # # # # # # # # # # # # # # # # # # # # # # to save database # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #");
            this.saveDB(operLog);
            log.info("# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #");
        } catch (Exception exp) {
            // Record local exception logs
            log.error("== Pre-notification exception ==");
            log.error("Exception message :{}", exp.getMessage()); exp.printStackTrace(); }}/** * Get the method description in the annotation for the Controller layer annotation **@paramThe log log *@paramOperLog Operation log *@throws Exception
     */
    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception {
        // Set the action
        operLog.setActionType(log.actionType().ordinal());
        // Set the title
        operLog.setModule(log.module());
        // Set the operator category
        operLog.setOperatorType(log.operatorType().ordinal());
        // Whether to save request, parameters, and values
        if (log.saveParameter()) {
            // Get the parameter information and pass it to the database.setRequestValue(joinPoint, operLog); }}/** * get the request parameters and place them in log **@paramOperLog Operation log *@throwsThe Exception Exception * /
    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception {
        String requestMethod = operLog.getRequestMethod();
        // Post and put requests come out
        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
            String params = argsArrayToString(joinPoint.getArgs());
            operLog.setOperParam(StrUtil.sub(params, 0.2000));
        } else {
            Restful style: {id} Parameter is obtainedHttpServletRequest httpServletRequest = ServletUtils.getRequest(); Map<? ,? > paramsMap = (Map<? ,? >) httpServletRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);// Get other styles
            if (paramsMap.isEmpty()) {
                HashMap<String, Object> map = new HashMap<>();
                Enumeration enu = httpServletRequest.getParameterNames();
                while (enu.hasMoreElements()) {
                    String paraName = (String) enu.nextElement();
                    map.put(paraName, httpServletRequest.getParameter(paraName));
                }
                operLog.setOperParam(StrUtil.sub(map.toString(), 0.2000));
            } else {
                operLog.setOperParam(StrUtil.sub(paramsMap.toString(), 0.2000)); }}}/** * if there are annotations, if so, get */
    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if(method ! =null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }

    /** ** parameter assembly */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if(paramsArray ! =null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                if(! isFilterObject(paramsArray[i])) { Object jsonObj = JSON.toJSON(paramsArray[i]); params += jsonObj.toString() +""; }}}return params.trim();
    }

    /** * Determines whether the object needs to be filtered. * *@paramO Object information. *@returnReturn true if the object is to be filtered; Otherwise return false. * /
    public boolean isFilterObject(final Object o) {
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
    }


    /** * emulated save database **@param operLog
     */
    private void saveDB(SysOperLog operLog) { log.info(operLog.toString()); }}Copy the code

use

/ * * *@Description: Log operation *@Author: jianweil
 * @date: 2021/12/6 15:49 * /
@RestController
@RequestMapping("/do")
@Slf4j
public class DoSomethingController {

      // Join point: the rule that triggers pointcut configuration when the getXxx method is called
    @log (module = "QUERY ", actionType = actionType.QUERY, operatorType = operatorType.MANAGE, saveParameter = false)
    @GetMapping
    public String getXxx(@RequestParam String param) {
        log.info("Get request, parameter: {}", param);
        return param;
    }

    @log (module = "QUERY ", actionType = actionType.QUERY, operatorType = operatorType.MANAGE, saveParameter = true)
    @GetMapping("/{param}")
    public String getXxx1(@PathVariable String param) {
        log.info("Get request, parameter: {}", param);
        return param;
    }

    @log (module = "add operation ", actionType = actionType.INSERT, operatorType = operatorType.MOBILE, saveParameter = true)
    @PostMapping
    public LoginUser postXxx(@RequestBody LoginUser loginUser) {
        log.info("Post request, parameter: {}", loginUser.toString());
        return loginUser;
    }

    @log (module = "modify ", actionType = actionType. UPDATE, operatorType = operatorType. MOBILE, saveParameter = true)
    @PutMapping
    public LoginUser updateXxx(@RequestBody LoginUser loginUser) {
        log.info("Put request, parameter: {}", loginUser.toString());
        return loginUser;
    }

    @log (module = "DELETE ", actionType = actionType.DELETE, operatorType = operatorType.MANAGE, saveParameter = true)
    @DeleteMapping("/{param}")
    public String deleteXxx(@PathVariable String param) {
        log.info("Delete request, parameter: {}", param);
        returnparam; }}Copy the code
  • ๐Ÿ‘๐Ÿป : have harvest, praise encouragement!
  • โค๏ธ : Collect articles, easy to look back!
  • ๐Ÿ’ฌ : Comment exchange, mutual progress!