The small half life of Java annotations

The main contents of this article include:

  1. What are annotations
  2. Composition of annotations
  3. Application of annotations

In fact, for those who just started to learn annotations, we should first understand the meaning and positioning of annotations, so that in our development process, we can also give full play to their role!

As for why the annotation of the small half of life, we see behind know!

What are annotations

As usual, take a look at Baidu’s explanation:

Starting with JDK5,Java has added support for metadata, also known as annotations. Annotations are somewhat different from annotations and can be understood as special tags in code that can be read and processed at compile, class load, and run time. Annotations allow developers to embed supplementary information in source code without changing the original code and logic.

(1) Basic understanding

In fact, this explanation is very good, and I personally like it very much. At the beginning of learning annotations WHEN I was baidu article, we all told me that annotations and annotations similar, and then began to compare, and then I fell into annotations that supplement the function, please get rid of this idea.

  1. A note is a mark

First of all, a note can be understood as a mark, notice! An annotation is a tag, it has no execution! An annotation is a tag, it has no execution! An annotation is a tag, it has no execution! The important thing is to say three times ha ~ in fact, I want to say is don’t silly open annotation code and then read his function source code word by word how to execute, can not see! Open the annotations and you will find some property content, there is no specific function to execute the relevant code, because its location is the tag, tag itself does not have any function!

  1. Annotations need to be found and then processed for the tag

If you recall what marking is, marking is a kind of positioning. For example, breaking points in code, placing ice cream cones in parking Spaces, wearing uniforms in school are actually marking. One might say that this marker works where does it not work? It tells us a lot of information! In fact, for tags to work, they need to be discovered by people who care about tags and then respond to events. Break points work in code because we debug and enable debug, and for other developers no one is going to care where the breakpoints are because they are not needed; The ice cream cone is found by the driver and accordingly avoids it, if you are a passer-by to put an ice cream cone for you actually has no sense of existence; The school uniform is for the relevant staff in the school to know that you are a student to control you, if you are an outsider, wearing a school uniform is actually irrelevant.

Therefore, annotations to remember the function, so we need to write a program to discover it and make the corresponding response, if we do not write a program to recognize and respond to it, then in fact the existence of annotations is meaningless! The following is the source code for @Component and the key code for handling it. Only the value attribute is defined in a class and the class of the annotation is captured in registerDefaultFilters() and added to the bean container

(2) Definition of annotations

  • @interface

So the first thing you need to do to define an annotation is you need an @interface tag so that’s the annotation type, it’s not interface, it’s not class. (But many people on the web have discovered by parsing bytecodes that the underlying annotation is still the definition of the interface, just for your information.

  • Yuan notes

The meaning of the meta – annotation is to describe the annotation, the meta – annotation can only be added above the annotation! This is a bit of a tricky thing to say and sounds like you don’t know much about it. In fact, it refers to the inherent properties of the annotations that you are currently customizing.

@Target()Function: Indicates where the current annotation can be placed, such as on a class (elementtype.type), on a METHOD (elementtype.method), in front of a PARAMETER (elementtype.parameter), etc.@DocumentedWhat it does: When generating a Javadoc document, it means that there will be annotations in the document, which is of little use to us.@InheritedWhat it does: When the class identified by the current annotation is inherited, the annotation can also be inherited.@RetentionPolicyFunction: There are only three types of markup annotations that retain the maximum lifespan, It only lives in. Java files (retentionPolicy.source), up to. Class files (retentionPolicy.class files), and always lives in RUNTIME (retentionPolicy.runtime).Copy the code

When customizing annotations, we can add meta annotations as needed to describe what our annotations look like, and the system will handle the meta annotations as we give them.

  • Annotation properties

If you are careful, you will find that the @override and @Component source codes do not define property variables, but methods. In fact, if you continue to look at other annotations, you will find the same thing. In the case of annotations, defining attributes is just like defining methods. As we said earlier, annotations themselves do not have the function of method implementation, so we can’t actually write anything about method implementation in annotations. The annotation attribute is actually like a highlighter, and the color is its attribute. It is because of the color difference that the “mark” can play a greater role, so sometimes we can add some attributes in the annotation “mark” to fill in, so that the information conveyed by the “mark” is more comprehensive!

We all know that in general we write properties in classes in this format

public String name;

This is what it says in the notes

String name();

  • Public and other visibility keywords are invalid and redundant when written in annotations
  • The attribute type is the “return type keyword” in the annotation
  • The attribute variable name is the “method name” in the annotation

If you define an annotation this way, then we have to fill in the annotation’s name property every time we write an annotation, and if we want it to be optional, we have to add the default value

String name() default "this is default name";

Second, annotation example analysis

Let’s take a few practical examples to show you, at least when we look at the annotated source code also know the general use of annotations

  • @RequestMapping
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
   String name(a) default "";
   @AliasFor("path")
   String[] value() default {};
   @AliasFor("value")
   String[] path() default {};
   RequestMethod[] method() default {};
   String[] params() default {};
   String[] headers() default {};
   String[] consumes() default {};
   String[] produces() default {};
Copy the code

I’m sure you’re familiar with this annotation, but if you haven’t used it before, we just want you to know how to use it correctly, what configuration we can do, and what information I can add to it.

@target ({elementType.type, elementType.method}) means that @requestMapping annotations can only be placed on classes and methods

@Retention(retentionPolicy.runtime) means @requestMapping annotations can always survive RUNTIME

And these annotations are preserved in the @Documented document for you to view

@ Mapping which we didn’t speak, he is not a yuan notes, that he is not native to describe an annotation, actually this is custom annotation framework, function on the annotation, so if you have not seen the comments don’t panic, great is likely to be the third party their own definition, view the source code you will find that you actually read it again, here but more reading! I believe you have the ability to interpret it

@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Mapping {
}
Copy the code

String name() default “”; You can add the name attribute, default is “”

@aliasfor (“path”) framework custom attribute, and it passes in the path attribute value (this annotation is valid to rename)

String[] value() default {}; You can add a value attribute, default is “”

@aliasfor (“value”) Framework custom attributes

String[] path() default {}; You can add the path attribute, default is []

RequestMethod[] method() default {}; You can add a method attribute, which defaults to [], and note that RequestMethod is of annotation type

String[] params() default {}; You can add params properties, default is []

String[] headers() default {}; You can add the headers attribute, default is []

String[] consumes() default {}; You can add Consumes. The default is [].

String[] produces() default {}; You can add the Produces attribute, which defaults to []

Usage:

We can just add an annotation and take no arguments, because here we’re going around and they all have default values

@RequestMapping
public class controller(a){}Copy the code

We can pass in some attribute values that override the default values

@RequestMapping(value = "/index")// override the default value of the value attribute "", pass in "/index"
public class controller(a){}Copy the code

And if we want to override value, we don’t have to write the name, it only works for value

@RequestMapping("/index")// override the default value of the value attribute "", pass in "/index"
public class controller(a){}Copy the code

But when we want to pass in multiple values, we must display all values explicitly

@RequestMapping(value = "/index", consumes = {"text/plain", "application/*"})It overwrites the consumes value, which is the default value for the value attribute. It passes in "/index". It consumes two values, and consumes an array through {}
public class controller(a){}Copy the code

Three, the use of annotations

That’s right. I specifically emphasized the use of the word here to show that annotation is a “mark” that needs to be “discovered” and then processed, so it’s probably easier to feel the positioning of annotations than it is to use them.

Before we customize, we need to think about what requirements we need to mark and identify and automate some of the processing. At present, annotations can be used in two ways, which are determined by their “life span”.

  • If the annotations are left until RUNTIME, then it is usually possible to use reflection to do some work with the annotations.
  • The annotations are reserved for the CLASS phase, which is similar to the SOURCE phase. There are few specific annotations reserved for this phase, and I can’t find them online. My personal opinion is that only ASM technology can be used
  • Annotations are reserved for the SOURCE stage, so we usually do some work with the annotation handler.

Really want to finish here so the processing of annotations, is difficult, it is a very large system, and I learn the whole annotation system because just met in the internship, so sparse inside hua of all learn and found that is very large, so I’m here to introduce some of the first technology, also let everybody introduction and don’t be confused.

(1) Pre-knowledge

To understand reflection, ASM technology, and annotation handlers, we need to know what process our original Java source files went through

  • .java => .class

This process is the compilation process, in fact, it is recommended that you can learn a bytecode file structure, after learning the process seems not so difficult to understand. First is lexical analysis, that is, to extract all the words, grammar analysis, will be. Java file to build into a AST abstract syntax tree, just as its name implies is like a tree, a hierarchy structure, and then there are the annotation processing, for some of the comments we can custom processing in advance, the process may change abstract tree, new files, So it’s possible to start from scratch in the first round, then parse, which is to see if the syntax is correct in the overall context, and finally generate bytecode files on disk.

  • .class loads memory

This process by the class loader to help load, deposited in the memory, memory allocation is what we need to know, to is for some constants, static content, information, and then heap storage building object, the program counter to point to the next instruction address, the virtual machine storage stack is produced for Yu Zhongtu various variables, The native method stack is used for native methods. It is important to know that when we create an object, we actually use the class information stored in the method area to create the object.

(2) reflection

Reflection is one of the most difficult things for beginners to understand, and the best way to understand it is to go through the whole process by typing code. Of course, there are also some people who experience it and find that reflection seems stupid to go through all the trouble to do it, and it is particularly abstract and complex. In fact, the essence of reflection is to process all kinds of logic from the existing class information. In the past, the process of creating objects was just a simple new, which is a process of “class whole” producing “object whole”.

But the reflection is that we can have the class information of each element, with all its attributes, methods and so on information, and determine treatment alone, it is because the class internal information differentiation, we can be of some characteristics of a particular class of processing, like batch processing, for certain attributes analysis of particle size small.

Reflections abound in the framework, and the flexibility of reflections creates endless possibilities! Also is so, for annotation process actually can also understand, we can get in a class by reflecting annotation information, if we want to note, we can get and extract key information, and then to need special processing, have we define annotation methods, for example, we will print log before this method performs, logging, and so on.

(3) of the ASM

ASM is not really relevant to this note, but I will expand on it. ASM is used for loading. Class files into memory, and its function is to modify the bytecode files directly. ASM is difficult to use because you need to be familiar with the bytecode structure to directly manipulate bytecode files. Direct processor bytecode is equivalent to generating code out of thin air. So going back to annotations, we can also identify annotations and do what we want.

(四)APT & AST

APT is the Annotation Procerss Tool, which is an Annotation processing step in the.java file to.class file in the figure above. This step is also added in JDk1.5. It was created so that annotations could be handled directly at compile time, not just in a run-time reflection way.

The general process of the annotation processor is to identify the element where the annotation is located, and then we can do some logic based on that element, but in fact, the popular play of APT is to produce Java files, it provides a Filer class for us to generate new Java files when we process the annotation, For example, the well-known Mybatis-Plus component can generate mapper and Service layer code with one key, which is very fragrant.

But in fact, most of the time, we do not want to generate another Java file, but simply want to modify the logic (in fact, I did not find any logic that can be modified when I queried the data at the beginning, I only identified and generated files from the beginning to the end, but did not mention that files can be modified. One day, I suddenly saw AST+APT). Will mention AST abstract syntax tree at this time, it is built in the process of syntax analysis, behind only to carry on the annotation processing, but in the process of annotation processing we can obtain abstract tree, so there is a way is in the process of annotation processing to generate Java files, we don’t we are in the process to obtain an abstract tree, changes to the abstract tree, This is the effect of modification! This is also how many components are currently played, most notably Lombok! Introducing Lombok to help us generate getters, setters, and so on is the principle. (Digression: Lombok before we use it to install the plugin, to the compiler to we is not an error in the process of writing code, even with a warning, or even if we actually wrote to deal with, as long as we don’t compile won’t add code, then we in the process of playing code if using the later add code, it will be an error, So Lombok solves this problem by installing plug-ins, which solves one of my big puzzles ———— why install plug-ins to introduce components!)

Four,

In fact, current annotations can help us a lot in development, like the @SpringBootApplication annotation of SpringBoot. One simple word actually helps us a lot, setting the path for package scanning, and then having a lot of annotations found and scanned, and then using reflection to register the bean. The second is to enable automatic configuration, simplify the configuration.

In fact, this article only introduces a small half of annotated life, because the practical application is complex and huge, so I will not expand here, of course, if you are still interested in, enthusiastic response, I also consider in the personal number (gold digging search – a little knowledge) to continue to expand.