Great wisdom teaches you to learn Java | Spring Boot. Use custom annotations to record operation logs

Posted by maxrisc on Fri, 24 Dec 2021 07:12:50 +0100

preface

No matter what application we develop, there will be a functional requirement - recording operation log. With the recording of operation log, we can not only ensure the completion of the application, but also trace the source through the operation log in case of system crash due to misoperation. It can be said that the function of recording operation log is indispensable in any application software. So, you can think about it. If we want to realize the function of recording operation logs, how should we implement it?

The simplest and crudest way is to add a line of code to each method to record the operation (inserting an operation log table is essentially an insert statement). Although we can realize the functions we need, the implementation process is more troublesome and prone to errors. At this time, it will be much more convenient to use custom annotations, which greatly simplifies our code and makes the code more readable. ๐Ÿ‘

So today I'd like to share with you how to use user-defined annotations to realize the function of "recording operation log" ๐Ÿคž

Using user-defined annotations to record operation logs

Implement custom annotations

Let's introduce Maven dependency first ๐Ÿ‘‡

<!-- SpringBoot Interceptor -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

Next, we implement an annotation class (annotations are similar to class and interface declarations in Java, but the keywords used are different. Declaration annotations use the @ interface keyword. On the underlying implementation, all defined annotations will automatically inherit the java.lang.annotation.Annotation interface.)

import java.lang.annotation.*;

/**
 * Custom annotation - implement operation logging
 * The code here is only for reference. During the development process, the required elements are added according to their own business function requirements
 * 
 * @description: Log
 * @author: Zhuang ba liziye
 * @create: 2021-12-21 12:47
 **/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
    /**
     * modular 
     */
    public String title() default "";

    /**
     * Operation type
     * 
     * BusinessType here is an enumeration class defined by myself
     * BusinessType.OTHER On behalf of other operations
     */
    public BusinessType businessType() default BusinessType.OTHER;
    
}

Let's say a few more words about the definition of annotation ๐Ÿ˜
โ‘  The access modifier must be public. If it is not written, it defaults to public.
โ‘ก The types of elements in a user-defined annotation can only be basic data type, String, Class, enumeration type, annotation type (reflecting the nesting effect of annotations) and a one bit array of the above types.
โ‘ข Default in the custom annotation represents the default value.
โ‘ฃ The @ Target annotation on the custom annotation is used to limit which Java elements the custom annotation can be applied to. ElementType is an enumeration type, and its source code is as follows ๐Ÿ‘‡

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

โ‘ค The @ Retention annotation on the custom annotation is used to define its declaration period. The life cycle of annotations has three stages: source file stage; Compilation phase; Operation phase. RetentionPolicy is also an enumeration type, and its source code is as follows ๐Ÿ‘‡

ublic enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

โ‘ฅ @ Documented on the custom annotation is a tag annotation indicating that the custom annotation should be recorded by JavaDoc tool. By default, JavaDoc records do not include annotations, but if @ Documented is specified when declaring annotations, the annotations will be processed by tools such as JavaDoc, so annotation type information will also be generated into JavaDoc documents.

Next, we need to define an aspect class to further realize the function of custom annotation. The code is as follows ๐Ÿ‘‡ (only important codes are posted here)

/**
 * Custom annotation - operation logging processing
 * The code here is for reference only. During the development process, add the required business logic according to your own business function requirements
 *
 * @description: Log
 * @author: Zhuang ba liziye
 * @create: 2021-12-22 13:07
 **/
@Aspect
@Component
public class LogAspect
{
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    // Configure the weaving point - xxx to represent the storage location of custom annotations, such as: com test. annotation. Log
    @Pointcut("@annotation(xxxx)")
    public void logPointCut()
    {
    }

    /**
     * Execute the code here after processing the request
     *
     * @param joinPoint Tangent point
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
    {
        handleLog(joinPoint, controllerLog, null, jsonResult);
    }

    /**
     * If an exception occurs while processing the request, execute the code here after throwing the exception
     * 
     * @param joinPoint Tangent point
     * @param e abnormal
     */
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
    {
        handleLog(joinPoint, controllerLog, e, null);
    }

	/**
     * Log processing
     */
    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
    {
        try
        {
            //Here is the specific business logic for processing logs
            //Finally, insert the operation information into the operation log table
        }
        catch (Exception exp)
        {
            // Record local exception log
            log.error("**** An exception occurred ****");
            log.error("Abnormal information:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }
}

Here we mainly explain the functions of various annotations in the aspect class:
โ‘  @ Aspect: an identifying annotation indicating that the current class is an Aspect that can be read by the container.
โ‘ก @ Component: indicates that this class is managed by Spring. It can be understood as injecting this class into Spring (just like injecting bean s into Spring).
โ‘ข @ Pointcut: Pointcut is the trigger condition of implantation section. The definition of each Pointcut includes two parts: an expression and a method signature. Method signature must be public and void. The method in Pointcut can be regarded as a marker symbol referenced by the cut. Because the expression is not intuitive, we can name this expression by means of method signature. Therefore, the method in Pointcut only needs the method signature, and does not need to write the actual code in the method body.
โ‘ฃ @ AfterReturning: Post enhancement, equivalent to AfterReturningAdvice. Adding this annotation to the method means that the method will be executed when the method exits normally.
โ‘ค @ AfterThrowing: exception throwing enhancement, which is equivalent to ThrowsAdvice. Adding this annotation to the method means that this method will be executed when the method throws an exception.
โ‘ฅ The functions of pointcut/value attributes are the same. They both belong to the entry expression corresponding to the specified entry point. Similarly, it can be either an existing pointcut or a pointcut expression can be defined directly. When the pointcut attribute value is specified, the value attribute value will be overwritten.
โ‘ฆ returning: this attribute specifies a formal parameter name, which is used to indicate that a formal parameter with the same name can be defined in the method, and this formal parameter can be used to access the return value of the target method. It should be noted that if the type is specified when defining the formal parameter in the method, the restriction target method must return a value of this type or no value.

So far, our custom annotations have been configured. Finally, let's take a look at how to use custom annotations~

Use custom annotations

It's easy to use custom annotations in the same way as other annotations ๐Ÿ‘‡

As long as we add a configured custom annotation to the method that needs to record the operation log (don't forget to assign a value to the field in the custom annotation ~), it can be used. Every time we request the method, it will help us record this operation.

P.S. Although the process of defining user-defined annotations is a little troublesome, it can not only improve the coding efficiency, but also instantly improve the strength of the code ๐Ÿ’ช

Summary

My experience is limited, and some places may not be particularly good. If you think of any problems when reading, please leave a message in the comment area, and we will discuss it later ๐Ÿ™‡ ‍

I hope you can use your lovely hands and give a wave of praise + attention (โœฟโ—กโ€ฟโ—ก) to let more children see this article ~ crab crab yo (โ— 'โ—ก' โ—)

If there are errors in the article, you are welcome to leave a message for correction; If you have a better and more original understanding, you are welcome to leave your valuable ideas in the message area.

When you are hit, remember your precious and resist malice;
When you are confused, believe in your precious and put aside gossip;
Love what you love, do what you do, listen to your heart and ask nothing

Topics: Java Spring Spring Boot