Spring’s source code is full of annotations, and understanding what annotations are will help you understand what follows.

Create custom annotations

Using IDEA, the new Java Class displays the following dialog, select the Annotation, enter the file name, and create a custom Annotation.

public @interface MyLog {
    
}
Copy the code

Then we create a Car class that uses the annotations we created.

import lombok.extern.slf4j.Slf4j;

@Slf4j
@MyLog
public class Car {

    public int chang;

    public void didi(a){
        log.info("didi"); }}Copy the code

It’s simple, it has a Chang attribute and a Didi method, and as you can see above the class, it uses a @slf4j annotation provided by Lombok, which is used to output logs, and you can see that there is a log.info() in the Didi method. Hey, that’s what this annotation provides.

In addition, the @mylog above the class is our own annotation.

The value of the annotation

If we use @service (“carService”), we can see that the @service annotation has a value. Can we use it? Can.

But, obviously, it was wrong

In this case, just say String value() default “”; It turns out to be like this, and that’s it.

public @interface MyLog {
    String value(a) default "";
}
Copy the code

I want multiple values, for example text, String text() default “”;

Another error. This is because value is a special value that can be omitted if it is alone, but must be written like this if it has multiple values:

Ok, now that it works, how do I get these two values?

Let’s create A test class with A method called isAnnotationPresent() to see if an annotation of type B is on class A.

@Slf4j
public class Test {
    public static void main(String[] args) {
        Class cls = Car.class;
        if (cls.isAnnotationPresent(MyLog.class)) {
            MyLog myLog = (MyLog) cls.getAnnotation(MyLog.class);
            log.info( "value:"+myLog.value());
            log.info( "text:"+myLog.text()); }}}Copy the code

So we get the value and the text, ok, let’s see:

Process finished with exit code 0
Copy the code

What also have no

Obviously, it doesn’t go into the if statement. Why? And then we look down

Yuan notes @ Retention

What is a meta-annotation? Notes of notes. Think of it this way, I’m an annotation, AND I’m going to modify another class, so it’s not too much to modify me with another annotation, hey, that’s a meta-annotation.

Meta-annotations constrain some of the things about annotations, such as @Retention which dictates the Retention strategy of annotations.

As we all know, the.Java files that we write are source code, and then the compiled.class files, and then the virtual machine loads the class files, which corresponds to three different periods.

So annotations, too.

Policies have SOURCE, CLASS, and RUNTIME, which correspond to the three periods described above.

Why is that? Some annotations just need to appear in the source code and are no longer needed after compilation, such as @override, which serves only as a check for the developer, and will report an error when the Override method is incorrectly written.

There is also @slf4j mentioned earlier, you can look at the compiled Car. Class file, no.

Private static final Logger log = LoggerFactory.getLogger(car.class); This is the capability provided by the Lombok plug-in.

package com.example.demo.spring5;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@MyLog( value = "car", text = "xxxx" )
public class Car {
    private static final Logger log = LoggerFactory.getLogger(Car.class);
    public int chang;

    public Car(a) {}public void didi(a) {
        log.info("didi"); }}Copy the code

From the SOURCE code, we can see that the @slf4J annotation uses the SOURCE policy

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
public @interface Slf4j {
    String topic(a) default "";
}
Copy the code

The default value for @Retention

But if we created our own annotations and didn’t write anything, it must have a default value.

If we look at the car.class file, the @mylog annotation is there, the source code is there, but the runtime is not, then we can infer that the default policy is class. This can also be seen in the Retention source code annotations.

If no Retention annotation is present on an annotation type declaration, the retention policy defaults to {@code RetentionPolicy.CLASS}.

Ok, let’s try the RUNTIME

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

@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
    String value(a) default "";

    String text(a) default "";
}
Copy the code
14:19:20. [the main] INFO 596 com. Example. Demo. Spring5. Test - value: car 14:19:20. [the main] 607 INFO com.example.demo.spring5.Test - text:xxxx Process finished with exit code 0Copy the code

I finally got the value

Suddenly, we found that the annotation is only used in the class, that is used in the method, the property of the up?

Ok, now modify the Car class

@Slf4j
@MyLog(value="car",text="xxxx")
public class Car {

    @ MyLog (value = "100", the text = "length")
    public int chang;

    @mylog (value="didi",text=" didi")
    public void didi(a){
        log.info("didi"); }}Copy the code

Test classes are also revamped

import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

@Slf4j
public class Test {
    public static void main(String[] args) {
        Class cls = Car.class;
        try {
            // Get annotations on methods
            Method didi = cls.getDeclaredMethod("didi");
            if (didi.isAnnotationPresent(MyLog.class)) {
                MyLog annotation = didi.getAnnotation(MyLog.class);
                log.info("Value on method {} : {}",didi.getName(),annotation.value());
                log.info("Text value on method {} : {}",didi.getName(),annotation.text());
            }

            // Get the annotation on the property
            Field chang = cls.getDeclaredField("chang");
            if (chang.isAnnotationPresent(MyLog.class)) {
                MyLog annotation = chang.getAnnotation(MyLog.class);
                log.info("Value value on attribute {} : {}",chang.getName(),annotation.value());
                log.info("Text value on property {} : {}",chang.getName(),annotation.text()); }}catch(NoSuchMethodException | NoSuchFieldException e) { e.printStackTrace(); }}}Copy the code

Look at the output:

14:25:23.158[the main] INFO com. Example. Demo. Spring5. Didi the value of the value of the Test methods: didi14:25:23.163[the main] INFO com. Example. Demo. Spring5. Didi Test methods on the text value: print content14:25:23.163[the main] INFO com. Example. Demo. Spring5. Test - attribute value on chang value:100
14:25:23.163[the main] INFO com. Example. Demo. Spring5. Test - the text on the chang attribute values: the length of the Process finished with exit code0
Copy the code

Well, I just want this annotation to be used only on classes, is there any way?

There are!

Yuan notes @ Target

This annotation limits the scope of the annotation. Its values include TYPE, METHOD, FIELD, and CONSTRUCTOR. METHOD is applied to methods, TYPE is applied to classes, and FIELD is applied to properties.

Let’s add a meta annotation @target (elementtype.type)

You can now see that applications to properties or methods will report errors.

Ok, that’s all for this one.