[SpringMVC] Custom annotations are used in combination with AOP

Table of contents

1. Custom annotations for SpringMVC

1.1 Introduction to Java annotations

1.2 Why use annotations

1.3 Classification of annotations⭐

1.3.1 JDK basic annotations

1.3.2 JDK meta-annotations 

1.3.3 Custom annotations 

1.4 Three use cases of custom annotations

1.4.1 Case 1 (obtaining annotation values ​​on classes and methods)

1.4.2 Case 2 (obtaining the annotation attribute value on the class attribute)

1.4.3 Case 3 (obtaining attribute values ​​corresponding to parameter modification annotations)

2. Application of Aop custom annotations  

2.1 Custom annotation class

2.2 Aspect class

2.3 Controller layer code

2.4 Testing


1. Custom annotations for SpringMVC

1.1 Introduction to Java annotations

        Annotation is a metadata mechanism of the Java language, which provides a way to add additional information to the code. Annotations can be used to mark specific elements of code, such as classes, methods, fields, parameters, etc., for processing at compile time, run time, or by tools.

Annotation related classes are included in the java.lang.annotation package.

1.2 Why use annotations

The main purpose of using annotations is to provide more metadata information for processing at compile time or runtime. Annotations can be used in the following areas:

  1. Compile-time processing: Annotations can be recognized and processed by the compiler at compile time. By adding annotations to the code, we can tell the compiler to perform specific operations, such as generating additional code, performing static checks, generating documentation, etc. For example, the @Test annotation in the JUnit framework is used to mark test methods, which will be recognized by the JUnit runner at compile time and execute the corresponding test.

  2. Runtime processing: Annotations can be read and processed through the reflection mechanism while the program is running. By reading annotations, we can obtain metadata information in the code and execute corresponding logic based on the definition of the annotations. For example, the @Autowired annotation in the Spring framework is used to automatically inject dependencies . By reading the annotations, the Spring container can automatically inject dependencies into the corresponding objects.

  3. Tool processing: Annotations can be read and processed by tools to achieve specific functions. For example, the JavaDoc tool can read annotations in the code and generate corresponding documentation. Other tools, such as code generators, static analysis tools, etc., can also use annotations to implement specific functions.

The benefits of using annotations include:

  1. Provide more metadata information: Annotations can add additional metadata information to the code, making the code richer and more readable. Through annotations, we can mark the specific meaning, behavior and rules of the code to improve the understandability and maintainability of the code.

  2. Simplify the development process: Annotations can simplify the development process and reduce repeated code and configuration. By using annotations, we can automate some common tasks, such as dependency injection, configuration parsing, route mapping, etc., to improve development efficiency.

  3. Enhance the reliability and security of the code: Annotations can be used for static checks and constraints to ensure the correctness and security of the code. By adding annotations to the code, we can verify it at compile time or run time and avoid some common errors and problems.

        In short, annotations are a powerful metadata mechanism that can add additional information and behavior to the code, improving the readability, maintainability and reliability of the code. By using annotations, we can simplify the development process, improve development efficiency, and achieve more flexible and scalable functions.

1.3 Classification of annotations⭐

1.3.1 JDK basic annotations

        JDK basic annotations are a set of predefined annotations provided in the Java Development Kit (JDK) for marking specific elements of code. These annotations include:

  1. @Override: Used to mark methods that override (override) methods in the parent class. When a method uses this annotation, the compiler checks whether the method correctly overrides the method in the parent class.

  2. @Deprecated: Used to mark deprecated methods, classes or fields. When a method or class is marked as obsolete, the compiler will issue a warning to remind developers that the method or class is no longer recommended.

  3. @SuppressWarnings: used to suppress warning messages generated by the compiler. You can use this annotation on a method, class, or entire block of code to ignore specific types of warnings.

1.3.2 JDK meta-annotations 

        JDK meta-annotations are annotations used to annotate other annotations. They provide more metadata and behavior to define the behavior of the annotations. Four meta-annotations are provided in the JDK:

  1. @Retention: used to specify the life cycle of annotations. Can be set to SOURCE (visible only in source code), CLASS (visible at compile time), or RUNTIME (visible at runtime).

  2. @Target: used to specify the target element type to which the annotation can be applied. Can be set to TYPE (class, interface, enumeration), METHOD (method), FIELD (field), etc.

  3. @Documented: used to specify whether the annotation is included in the Java document. If an annotation is modified with the @Documented annotation, its information will be included in the generated document.

  4. @Inherited: used to specify whether the annotation can be inherited. If an annotation is modified by the @Inherited annotation, then its subclasses will automatically inherit the annotation (not commonly used) .

@Target: Specify the location where the modified Annotation can be placed (modified target)
@Target(ElementType.TYPE) //Interface, class
@Target(ElementType.FIELD) //Attribute
@Target(ElementType.METHOD) //Method
@Target(ElementType.PARAMETER) //Method parameter
@Target(ElementType.CONSTRUCTOR) //Constructor function
@Target(ElementType.LOCAL_VARIABLE) //Local variable
@Target(ElementType.ANNOTATION_TYPE) //Annotation
@Target(ElementType.PACKAGE) //Bag


Note: Multiple positions can be specified, for example:
@Target({ElementType.METHOD, ElementType.TYPE}), that is, this annotation can be used on methods and classes 

1.3.3 Custom annotations 

        Custom annotations are annotations created by developers based on their own needs. Through custom annotations, developers can add specific metadata information to the code and define corresponding processing logic. The steps to create custom annotations include:

  1. Use the @interface keyword to define an annotation type.
  2. Define required elements in annotations, which can include basic types, enumeration types, Class types, annotation types, etc.
  3. Use meta-annotations to modify annotations, such as @Retention, @Target, etc., to define the life cycle and usage scope of the annotations.
  4. When you use custom annotations in your code, you can obtain the element value of the annotation through reflection, and perform corresponding processing based on the definition of the annotation.

To create a custom annotation, you need to use Java's annotation mechanism. Here is a simple example showing how to create a custom annotation:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation {
    // 在这里定义注解的属性
    String value();
}

In the above example, we created an CustomAnnotationannotation called. It has an attribute valuethat can be used to pass some custom information.

        Through custom annotations, developers can implement more flexible and scalable functions, such as custom validation rules, logging, permission control, etc. Custom annotations can be used at the class, method, field, parameter, etc. levels to meet different needs.

1.4 Three use cases of custom annotations

Annotations (Annotations can be divided into two categories according to whether they contain member variables):

1. Marker Annotation: This kind of annotation has no member variables. They only provide information through their own existence.

For example: the @Override annotation in Java is a mark annotation, which is used to mark methods that override (override) methods in the parent class.

2. Meta Annotation: This annotation contains member variables, which can accept and provide more metadata information. Metadata annotations can carry additional data or parameters in addition to marking specific elements of the code. Through metadata annotations, we can add more metadata information to the code for processing at compile time, runtime or through tools. Metadata annotations can be used for configuration, constraints, verification, etc.

For example: the @RequestMapping annotation in the Spring framework is a metadata annotation. It can not only mark the request processing method, but also specify the requested URL path, request method, request parameters, etc.

1.4.1  Case 1 (obtaining annotation values ​​on classes and methods)

1. Define an enumeration class: used to represent a fixed set of values.

package com.ycxw.model;

public enum  TranscationModel {
    Read, Write, ReadWrite
}

2. Define three classes with different annotation methods:

MyAnnotation1 :  

package com.ycxw.annotation;

import java.lang.annotation.*;

/**
 * MyAnnotation1注解可以用在类、接口、属性、方法上
 * 注解运行期也保留
 * 不可继承
 */
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation1 {
    String name();
}

MyAnnotation2 :  

package com.ycxw.annotation;

import com.ycxw.model.TranscationModel;

import java.lang.annotation.*;

/**
 *  MyAnnotation2注解可以用在方法上
 *  注解运行期也保留
 *  不可继承
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {
    TranscationModel model() default TranscationModel.ReadWrite;
}

MyAnnotation3 :  

package com.ycxw.annotation;

import com.ycxw.model.TranscationModel;

import java.lang.annotation.*;


/**
 * MyAnnotation3注解可以用在方法上
 * 注解运行期也保留
 * 可继承
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {
    TranscationModel[] models() default TranscationModel.ReadWrite;
}

 Demo1 test class:  Get annotation values ​​on classes and methods

package com.ycxw.annotation.demo;

import com.ycxw.annotation.MyAnnotation1;
import com.ycxw.annotation.MyAnnotation2;
import com.ycxw.annotation.MyAnnotation3;
import com.ycxw.model.TranscationModel;

/**
 * 获取类与方法上的注解值
 */
@MyAnnotation1(name = "abc")
public class Demo1 {

    @MyAnnotation1(name = "xyz")
    private Integer age;

    @MyAnnotation2(model = TranscationModel.Read)
    public void list() {
        System.out.println("list");
    }

    @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})
    public void edit() {
        System.out.println("edit");
    }
}

 Demo1Test test class:

package com.ycxw.annotation.demo;

import com.ycxw.annotation.MyAnnotation1;
import com.ycxw.annotation.MyAnnotation2;
import com.ycxw.annotation.MyAnnotation3;
import com.ycxw.model.TranscationModel;
import org.junit.Test;

public class Demo1Test {
    @Test
    public void list() throws Exception {
//        获取类上的注解
        MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);
        System.out.println(annotation1.name());//abc

//        获取方法上的注解
        MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);
        System.out.println(myAnnotation2.model());//Read

//        获取属性上的注解
        MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);
        System.out.println(myAnnotation1.name());// xyz
    }

    @Test
    public void edit() throws Exception {
        MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);
        for (TranscationModel model : myAnnotation3.models()) {
            System.out.println(model);//Read,Write
        }
    }
}

The result of running the list method:

Results of running the edit method:

1.4.2  Case 2 (obtaining the annotation attribute value on the class attribute)

1. Custom annotation class:

package com.ycxw.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {
    String value() default "默认value值";

    String what() default "这里是默认的what属性对应的值";
}

2. Define the test class: get the annotation attribute value on the class attribute

package com.ycxw.annotation.demo2;

import com.ycxw.annotation.TestAnnotation;

/**
 * 获取类属性上的注解属性值
 */
public class Demo2 {
    @TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1")
    private static String msg1;

    @TestAnnotation("这就是value对应的值1")
    private static String msg2;

    @TestAnnotation(value = "这就是value对应的值2")
    private static String msg3;

    @TestAnnotation(what = "这就是what对应的值")
    private static String msg4;
}

 3. Test

package com.ycxw.annotation.demo2;

import com.ycxw.annotation.TestAnnotation;
import org.junit.Test;

public class Demo2Test {
    @Test
    public void test1() throws Exception {
        TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);
        System.out.println(msg1.value());
        System.out.println(msg1.what());
    }

    @Test
    public void test2() throws Exception{
        TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);
        System.out.println(msg2.value());
        System.out.println(msg2.what());
    }

    @Test
    public void test3() throws Exception{
        TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);
        System.out.println(msg3.value());
        System.out.println(msg3.what());
    }

    @Test
    public void test4() throws Exception{
        TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);
        System.out.println(msg4.value());
        System.out.println(msg4.what());
    }
}

1.4.3 Case 3 (obtaining attribute values ​​corresponding to parameter modification annotations)

1. Create custom annotations:

package com.ycxw.annotation;

import java.lang.annotation.*;

/**
 * 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空
 */
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {
    boolean value() default false;
}

2. Create a test class: obtain the attribute value corresponding to the parameter modification annotation

package com.ycxw.annotation.demo3;

import com.ycxw.annotation.IsNotNull;

/**
 * 获取参数修饰注解对应的属性值
 */
public class Demo3 {

    public void hello1(@IsNotNull(true) String name) {
        System.out.println("hello:" + name);
    }

    public void hello2(@IsNotNull String name) {
        System.out.println("hello:" + name);
    }
}

3. Test

package com.ycxw.annotation.demo3;

import com.ycxw.annotation.IsNotNull;
import org.junit.Test;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class Demo3Test {

    @Test
    public void hello1() throws Exception {
        Demo3 demo3 = new Demo3();
        for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            if(annotation != null){
                System.out.println(annotation.value());//true
            }
        }
    }

    @Test
    public void hello2() throws Exception {
        Demo3 demo3 = new Demo3();
        for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            if(annotation != null){
                System.out.println(annotation.value());//false
            }
        }
    }

    @Test
    public void hello3() throws Exception {
//        模拟浏览器传递到后台的参数 解读@requestParam
        String name = "zs";
        Demo3 demo3 = new Demo3();
        Method method = demo3.getClass().getMethod("hello1", String.class);
        for (Parameter parameter : method.getParameters()) {
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            if(annotation != null){
                System.out.println(annotation.value());//true
                if (annotation.value() && !"".equals(name)){
                    method.invoke(demo3,name);
                }
            }
        }
    }
}

 

2. Application of Aop custom annotations  

2.1 Custom annotation class

package com.ycxw.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
    String desc();
}

2.2  Section class

package com.ycxw.aspect;

import com.ycxw.annotation.MyLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);

    /**
     * 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类
     */
    @Pointcut("@annotation(com.ycxw.annotation.MyLog)")
    private void MyValid() {
    }

    @Before("MyValid()")
    public void before(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        logger.debug("[" + signature.getName() + " : start.....]");
        System.out.println("[" + signature.getName() + " : start.....]");

        MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);
        logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());
        System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc());
    }
}

2.3  Controller layer code

package com.ycxw.web;

import com.ycxw.annotation.MyLog;
import org.springframework.stereotype.Component;

@Component
public class LogController {
    @MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")
    public void testLogAspect(){
        System.out.println("记录日志...");
    }
}

2.4 Testing

Access address: http://localhost:8080/log/mylog

Guess you like

Origin blog.csdn.net/Justw320/article/details/132886879