Table of contents
1. Introduction to Java annotations
2. Java annotation classification
2. Custom annotations (used in SpringMVC)
Case 1: (Getting annotation values on classes and methods)
Deployment test (define three constants)
Define and write three custom label classes
Custom label 01 (MyAnnotation1.java)
Custom label 02 (MyAnnotation2.java)
Custom label 03 (MyAnnotation3.java)
Case 2: (Get the annotation attribute value on the class attribute)
Case 3; (Get the attribute value corresponding to the parameter modification annotation)
hello1() method test result (name attribute is empty)
3. Aop custom annotation case (key points)
Preface
Hello fellow veterans, those who have read my previous blogs all know that in previous blog sharings we learned about JSON return types, exception handling mechanisms, JSR303, interceptors, etc. Today I will take you all to explore a new field - custom annotations .
1. Introduction to Java annotations
1. What are Java annotations?
Java annotations are a special syntax element of the Java language that can be used to add additional metadata information to the code. Annotations can be used on various program elements such as classes, methods, variables, parameters, etc. The role of annotations is to provide additional information to other parts of the program so that the compiler, parser, or runtime environment can perform corresponding processing based on the annotation information when processing these program elements.
Java annotations usually use custom annotations or built-in predefined annotations , such as
@Override
,@Deprecated
etc. You can also customize annotations as needed.The advantage of using Java annotations is that you can add more semantic information to the code through annotations, improving the readability and maintainability of the code . Annotations can also be used to implement the functions of some frameworks, libraries or tools, such as JUnit testing framework, Spring framework, etc.
2. Java annotation classification
2.1 JDK basic annotations
Some basic annotations provided by the JDK provide compiler-level information and guidance, which can help developers write more accurate and efficient code.
annotation | Annotation description |
@Override | Used to annotate methods, indicating that the method overrides the parent class's method . @Override The compiler will give a warning when a method is marked with an annotation but does not actually override the parent class method. |
@Deprecated | Used to mark obsolete methods, classes, fields, etc. Indicates that this item is deprecated and may be removed or replaced in future versions. |
@SuppressWarnings | Used to suppress certain warnings and can be applied to classes, methods, variables, etc. This annotation can accept one or more parameters that specify the type of warning to suppress . |
@SafeVarargs | Used to mark a method as a type- safe variadic method . The compiler will give a warning when using variadic methods, but @SafeVarargs this warning can be suppressed by using annotations. |
@FunctionalInterface | Used to mark an interface to indicate that the interface is a functional interface. A functional interface is an interface that contains only one abstract method and is often used in Lambda expressions and functional programming . |
@SuppressWarnings("serial") | Used to suppress unserialized warnings . In a custom serializable class, if serialVersionUID a field is not specified, the compiler will give a warning. @SuppressWarnings("serial") This warning can be suppressed by using annotations. |
2.2 JDK meta-annotations
JDK meta-annotations refer to a set of annotations provided in the Java Development Kit (JDK) for marking and defining other annotations. They are predefined annotations provided by the Java language to provide more control and additional information when writing and using custom annotations.
annotation | Annotation description |
@Retention | Used to specify the retention policy of annotations. There are three retention policies to choose from, namely RetentionPolicy.SOURCE, RetentionPolicy.CLASS and RetentionPolicy.RUNTIME. Default is RetentionPolicy.CLASS . (Define retention policy for annotations) |
@Documented | Used to specify whether the element modified by this annotation needs to be included in the Java document. (The specified modified Annotation can be extracted into a document by the javadoc tool.) |
@Target | Used to specify the target element type to which the annotation applies, which can be a class, method, field, etc. Common values include ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, etc. |
@Inherited | Used to specify whether the class modified by this annotation can be inherited by subclasses. By default, it will not be inherited by subclasses. (Specified that the modified Annotation will have inheritance) |
@Repeatable | Used to specify whether the annotation can be applied repeatedly to the same element, so as to achieve the effect of annotating the element multiple times. |
Note:
@Retention:
@Retention(RetentionPolicy.SOURCE) //The annotation only exists in the source code and is not included in the class bytecode file.
@Retention(RetentionPolicy.CLASS) //Default retention policy, annotations will exist in the class bytecode file, but cannot be obtained at runtime.
@Retention(RetentionPolicy.RUNTIME) //The annotation will exist in the class bytecode file and can be obtained through reflection at runtime.
@Target:
@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) //Package
For example:
@Target({ElementType.METHOD, ElementType.TYPE}), that is, this annotation can be used on methods and classes
2.3 Custom annotations
Custom annotations refer to using developer-defined annotations (Annotation) in Java. Annotations are a type of metadata that provide additional information about a program and can be used to add markup, configuration, and dynamic behavior to the code.
Through custom annotations, developers can add additional information and semantics to elements such as classes, methods, and fields according to their own needs. Custom annotations need to be implemented using the annotation metaprogramming mechanism provided by Java and using specific annotation elements and annotation processors.
The definition method of custom annotations is similar to that of ordinary interfaces. Use keywords
@interface
to define annotations, and then define annotation elements in them.
Case:
import java.lang.annotation.*;
@Target(ElementType.TYPE) // 指定注解应用的目标类型(这里是类)
@Retention(RetentionPolicy.RUNTIME) // 指定注解保留的策略(这里是运行时)
public @interface MyAnnotation {
String value() default ""; // 定义注解元素
}
The above code example defines a MyAnnotation
custom annotation named. This annotation can be applied to a class (ElementType.TYPE) and the annotation information is retained at runtime (RetentionPolicy.RUNTIME). The annotation defines an value
annotation element named.
2. Custom annotations (used in SpringMVC)
Case explanation
Case 1: (Getting annotation values on classes and methods)
Deployment test (define three constants)
Create an annotation folder, create a TranscationModel.java class and test class under the file
TranscationModel.java
package com.yx.annotation;
public enum TranscationModel {
Read, Write, ReadWrite
}
Corresponding test class
package com.yx.annotation;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
* @create 2023-09-15 16:42
* 测试类
*
*/
public class Test01 {
public static void main(String[] args) {
System.out.println(TranscationModel.Read);
System.out.println(TranscationModel.Write);
System.out.println(TranscationModel.ReadWrite);
}
}
operation result
Define and write three custom label classes
Custom label 01 (MyAnnotation1.java)
package com.yx.annotation.demo01;
import java.lang.annotation.*;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
* @create 2023-09-15 16:42
* 注解1
* MyAnnotation1注解可以用在类、接口、属性、方法上
* 注解运行期也保留
* 不可继承
*/
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation1 {
String name();
}
Custom label 02 (MyAnnotation2.java)
package com.yx.annotation.demo01;
import java.lang.annotation.*;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
* @create 2023-09-15 16:42
* 注解02
* MyAnnotation2注解可以用在方法上
* 注解运行期也保留
* 不可继承
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {
TranscationModel model() default TranscationModel.ReadWrite;
}
Custom label 03 (MyAnnotation3.java)
package com.yx.annotation.demo01;
import java.lang.annotation.*;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
* @create 2023-09-15 16:42
* 注解03
* MyAnnotation3注解可以用在方法上
* 注解运行期也保留
* 可继承
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {
TranscationModel[] models() default TranscationModel.ReadWrite;
}
Related test categories
Demo1.java
package com.yx.annotation.demo01;
/**
* @author 小李飞刀
* @site www.javaxl.com
*
* 获取类与方法上的注解值
*/
@MyAnnotation1(name = "muyi")
public class Demo1 {
@MyAnnotation1(name = "xixi")
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
package com.yx.annotation.demo01;
import org.junit.Test;
/**
* @author 小李飞刀
* @site www.javaxl.com
*/
public class Demo1Test {
@Test
public void list() throws Exception {
// 获取类上的注解
MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);
System.out.println(annotation1.name());//muyi
// 获取方法上的注解
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());// xixi
}
@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
}
}
}
Test Results
list() method test results
edit() method test results
Case 2: (Get the annotation attribute value on the class attribute)
What is tested is the default value of value and the assignment of default default value.
Custom label class written
package com.yx.annotation.demo02;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
*/
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {
String value() default "默认value值";
String what() default "这里是默认的what属性对应的值";
}
Test Case
package com.yx.annotation.demo02;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
* 获取类属性上的注解属性值
*/
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;
}
Test paper code
package com.yx.annotation.demo02;
import org.junit.Test;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
*/
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());
}
}
Test Results
test()02 test results
test()03 test results
test()04 test results
Case 3; (Get the attribute value corresponding to the parameter modification annotation)
Custom label class written
package com.yx.annotation.demo03;
import java.lang.annotation.*;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
* 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空
*/
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {
boolean value() default false;
}
Test Case
package com.yx.annotation.demo03;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
* 获取参数修饰注解对应的属性值
*/
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);
}
}
Test paper code
package com.yx.annotation.demo03;
import org.junit.Test;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
*/
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);
}
}
}
}
}
Test Results
hello1() method test results
hello2() method test results
hello3() method test results
hello1() method test result (name attribute is empty)
If the name attribute value is not given, the method will not be called.
3. Aop custom annotation case (key points)
Test Case
MyLog.java
package com.yx.annotation.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
String desc();
}
Section type
MyLogAspect.java
package com.yx.aspect;
import com.yx.annotation.aop.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;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
*/
@Component
@Aspect
public class MyLogAspect {
private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);
/**
* 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类
*/
@Pointcut("@annotation(com.yx.annotation.aop.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());
}
}
Controller class
LogController.java
package com.yx.web;
import com.yx.annotation.aop.MyLog;
import org.springframework.stereotype.Controller;
/**
* @author 君易--鑨
* @site www.yangxin.com
* @company 木易
*/
@Controller
public class LogController {
@MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")
public void testLogAspect(){
System.out.println("这里随便来点啥");
}
}
Test Results
Situation one:
This ends the blog sharing in this issue. I hope Lao Tie will pay attention and support.