What are annotations?
Annotations are metadata, which are used to describe classes, interfaces, methods, properties, etc. of java code, and then the application can do some actions according to the annotations. For example, the annotation @Service in Spring indicates that this is a service class, and then the Spring framework will create an instance for it, and set the key value and save it in the ApplicationContext according to the parameters of the annotation. These behaviors are all done by the Spring framework. Just provide metadata. For details, please refer to another article "Writing Simple Implementation Annotation SpringMVC Framework" . You can see that the function of the annotation is to mark it with a mark, indicating that this is a Service class and you want to deal with it, and provide some parameters to tell you how to deal with it. Annotations work just like xml configuration files.
Why introduce annotations?
Before (and after) Annotation, xml was widely used to describe metadata. Somehow some application developers and architects found that xml maintenance was getting worse and worse. They want to use something that is tightly coupled to the code, rather than a loosely coupled code description like xml. If you Google "xml vs. annotations", you'll see many debates on this issue. The most interesting thing is that xml configuration is actually introduced to separate code and configuration. The two viewpoints above may confuse you, they seem to constitute a kind of cycle, but each has its pros and cons. Below we use an example to understand the difference between the two.
If you want to set a lot of constant post-parameters for your application, in this case, xml is a good choice because it is not linked to specific code. If you want to declare a method as a service, then it is better to use an annotation, because in this case the annotation and the method need to be tightly coupled.
Many frameworks currently use a combination of xml and annotation to balance the pros and cons of the two.
Use of annotations
Java now has three built-in standard annotations
@Override, indicating that the current method definition will override the method in the superclass
@Deprecated indicates deprecated code
@SuppressWarnings turns off inappropriate compiler warnings
Java also provides four additional annotations, which are responsible for the creation of new annotations:
@Target : Indicates where the annotation can be used. Possible ElementType parameters are:
CONSTRUCTOR: Declaration of the constructor
FIELD: field declaration (including enum instances)
LOCAL_VARIABLE: local variable declaration
METHOD: Method declaration
PACKAGE: package declaration
PARAMETER: parameter declaration
TYPE: class, interface (including annotation types) or enum declaration
@Retention: Indicates at what level the annotation information needs to be saved. Optional RetentionPolicy parameters include:
SOURCE: The annotation will be discarded by the compiler
CLASS: Annotations are available in class files, but are discarded by the VM
RUNTIME: The VM will retain the annotation during runtime, so the information of the annotation can be read through the reflection mechanism.
@Document: include annotations in Javadoc
@Inherited: Allows subclasses to inherit annotations from parent classes
How to define an annotation:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Test { }
There are generally some elements in the annotation that represent some value. The elements of the annotation look like the methods of the interface , the only difference is that you can define a default value for it. Elements cannot have indeterminate values when used, that is, either have a default value, or provide the value of the element when used, and cannot use null as the default value. Annotation When there is only one element and the element name is value, you can use annotation to omit "value=" and write the value directly.
Define an element below
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno{ public String description() default "no description"; }
then use the annotation
public class UseAnno{ @UseCase public void userAnnoMethod() { }
Then process the annotation. The processing of the annotation is to obtain the annotation information through the reflection mechanism, and then perform specific processing according to the value of the annotation element.
public static void main(String[] args){ Method method = UseAnno.class.getMethod("useAnnoMethod"); MyAnno anno = method.getAnnotation(MyAnno.class); System.out.println(method.description()); //打印出“no description” }
The principle of annotation
An annotation in java is a special interface inherited from the interface `java.lang.annotation.Annotation`.
Let's take a look at a specific example.
Define an annotation:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno { int count() default 1; }
The compiled bytecode looks like this
Classfile /D:/platform/com.cq.platform.base/com.cq.platform.base.test/target/classes/com/cq/platform/base/test/annotation/MyAnno.class Last modified 2017-12-21; size 456 bytes MD5 checksum 3731139c896044ddb4f7dfc3d7092402 Compiled from "MyAnno.java" public interface com.cq.platform.base.test.annotation.MyAnno extends java.lang.annotation.Annotation SourceFile: "MyAnno.java" RuntimeVisibleAnnotations: 0: #14(#15=[e#16.#17]) 1: #18(#15=e#19.#20) minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION Constant pool: #1 = Class #2 // com/cq/platform/base/test/annotation/MyAnno #2 = Utf8 com/cq/platform/base/test/annotation/MyAnno #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Class #6 // java/lang/annotation/Annotation #6 = Utf8 java/lang/annotation/Annotation #7 = Utf8 count #8 = Utf8 ()I #9 = Utf8 AnnotationDefault #10 = Integer 1 #11 = Utf8 SourceFile #12 = Utf8 MyAnno.java #13 = Utf8 RuntimeVisibleAnnotations #14 = Utf8 Ljava/lang/annotation/Target; #15 = Utf8 value #16 = Utf8 Ljava/lang/annotation/ElementType; #17 = Utf8 TYPE #18 = Utf8 Ljava/lang/annotation/Retention; #19 = Utf8 Ljava/lang/annotation/RetentionPolicy; #20 = Utf8 RUNTIME { public abstract int count(); flags: ACC_PUBLIC, ACC_ABSTRACT AnnotationDefault: default_value: I#10}
As can be seen from the decompiled information, the annotation is an interface inherited from "java.lang.annotation.Annotation"
So how can an interface set properties? Simply put, java generates an instance of the "interface" 'MyAnno' for you through dynamic proxy (for the current entity, such as class, method, attribute domain, etc., this proxy object is a singleton), Then assign values to the properties of the proxy instance, so that configuration information can be obtained by radiation when the program is running (if the annotation is set to be visible at runtime).
How to achieve it?
Write a class that uses this annotation
@MyAnno(count=2) public class TestMain { public static void main(String[] args) { MyAnno anno = TestMain.class.getAnnotation(MyAnno.class); int b = anno.count(); } }
decompile code
Classfile /D:/platform/com.cq.platform.base/com.cq.platform.base.test/target/classes/com/cq/platform/base/test/annotation/TestMain.class Last modified 2017-12-21; size 900 bytes MD5 checksum 82c13adc58b44ced5b948006f28c0f15 Compiled from "TestMain.java" public class com.cq.platform.base.test.annotation.TestMain SourceFile: "TestMain.java" RuntimeVisibleAnnotations: 0: #43(#26=I#49) minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Class #2 // com/cq/platform/base/test/annotation/TestMain #2 = Utf8 com/cq/platform/base/test/annotation/TestMain #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Utf8 <init> #6 = Utf8() #7 = Utf8 Code #8 = Methodref #3.#9 // java/lang/Object."<init>":()V #9 = NameAndType #5:#6 // "<init>":()V #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lcom/cq/platform/base/test/annotation/TestMain; #14 = Utf8 main #15 = Utf8 ([Ljava/lang/String;)V #16 = Class #17 // com/cq/platform/base/test/annotation/MyAnno #17 = Utf8 com/cq/platform/base/test/annotation/MyAnno #18 = Methodref #19.#21 // java/lang/Class.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation; #19 = Class #20 // java/lang/Class #20 = Utf8 java/lang/Class #21 = NameAndType #22:#23 // getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation; #22 = Utf8 getAnnotation #23 = Utf8 (Ljava/lang/Class;)Ljava/lang/annotation/Annotation; #24 = InterfaceMethodref #16.#25 // com/cq/platform/base/test/annotation/MyAnno.count:()I #25 = NameAndType #26:#27 // count:()I #26 = Utf8 count #27 = Utf8 ()I #28 = Fieldref #29.#31 // java/lang/System.out:Ljava/io/PrintStream; #29 = Class #30 // java/lang/System #30 = Utf8 java/lang/System #31 = NameAndType #32:#33 // out:Ljava/io/PrintStream; #32 = Utf8 out #33 = Utf8 Ljava/io/PrintStream; #34 = Methodref #35.#37 // java/io/PrintStream.println:(I)V #35 = Class #36 // java/io/PrintStream #36 = Utf8 java/io/PrintStream #37 = NameAndType #38:#39 // println:(I)V #38 = Utf8 println #39 = Utf8 (I)V #40 = Utf8 args #41 = Utf8 [Ljava/lang/String; # 42 = Utf8 year #43 = Utf8 Lcom/cq/platform/base/test/annotation/MyAnno; #44 = Utf8 b #45 = Utf8 I #46 = Utf8 SourceFile #47 = Utf8 TestMain.java #48 = Utf8 RuntimeVisibleAnnotations #49 = Integer 2 { public com.cq.platform.base.test.annotation.TestMain(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/cq/platform/base/test/annotation/TestMain; public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: ldc #1 // class com/cq/platform/base/test/annotation/TestMain 2: ldc #16 // class com/cq/platform/base/test/annotation/MyAnno 4: invokevirtual #18 // Method java/lang/Class.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation; 7: checkcast #16 // class com/cq/platform/base/test/annotation/MyAnno 10: astore_1 11: aload_1 12: invokeinterface #24, 1 // InterfaceMethod com/cq/platform/base/test/annotation/MyAnno.count:()I 17: istore_2 18: getstatic #28 // Field java/lang/System.out:Ljava/io/PrintStream; 21: iload_2 22: invokevirtual #34 // Method java/io/PrintStream.println:(I)V 25: return LineNumberTable: line 5: 0 line 6: 11 line 7: 18 line 8: 25 LocalVariableTable: Start Length Slot Name Signature 0 26 0 args [Ljava/lang/String; 11 15 1 anno Lcom/cq/platform/base/test/annotation/MyAnno; 18 8 2 b I }
RuntimeVisibleAnnotations: 0:#43(#26=I#49)
It can be seen that the property setting of the annotation "MyAnno" is determined at compile time.
Then you can see the proxy class ""$Proxy1.class" under the com/sun/proxy package of the project. Where 'com.sun.proxy' is the default package name of the jdk dynamic proxy generation object. You can see this proxy class Inherited from the "java.lang.reflect.Proxy" class and implemented the "interface" MyAnno.
Article from: http://www.importnew.com/10294.html
https://www.cnblogs.com/huajiezh/p/5263849.html
Answer by Cao Xudong in https://www.zhihu.com/question/24401191