Deep learning Java annotations

Posted Jun 7, 202023 min read

All knowledge system articles, GitHub have been included, welcome to Star! Thanks again, I hope you enter the factory as soon as possible!

GitHub address: https://github.com/Ziphtracks/JavaLearningmanual

Java annotations

1. Overview of Java Annotations

Annotation, also known as metadata. A code-level description. It is a feature introduced in JDK1.5 and later versions, at the same level as classes, interfaces, and enumerations. It can be declared in front of packages, classes, fields, methods, local variables, method parameters, etc., used to explain and comment on these elements.

2. Classification of the role of annotations

  • Write the document: Generate the document from the metadata identified in the code [Generate document doc document]
  • Code analysis: Analyze the code through the metadata identified in the code [use reflection]
  • Compilation check: The metadata identified in the code allows the compiler to implement basic compilation checks [Override, etc.]

Writing documentation

First of all, we must know that there are three kinds of comments in Java, which are single-line comments, multi-line comments and document comments. In the document comments, there are also meta annotations starting with @, which are the comments based on the document comments. We can use the javadoc command to generate the doc document. At this time, the internal meta annotation of our document will also generate the corresponding document content. This is the role of writing documents.

Code analysis

One of our frequent uses also includes the use of reflection to analyze the code through the metadata identified in the code. We will explain this later.

Compile Check

As for the annotations marked in the code during compilation, it can be used to do specific compilation checks. It can check whether "do you act according to regulations" during compilation. If you do not act according to the annotations, it will be during compilation. Piaohong reports an error and gives a prompt message. It can provide a specification restriction for our code, avoiding our subsequent specification of too much code and function in the code. For example, the @Override annotation appears when we override the parent class(parent interface) method, which proves that our overriding method is a method inherited from the parent class(parent interface). If the method is slightly changed, an error will be reported; @FunctionInterface annotation It is checked at compile time whether it is a functional interface. If it does not follow its specifications, it will also report an error.

Three, jdk's built-in annotations

3.1 Built-in annotation classification

  • @Override: Marked on the member method, used to identify that the current method is to rewrite the parent class(parent interface) method, the compiler will check whether it complies with the rewriting rules when compiling the method, if not Comply, compile error.
  • @Deprecated: Used to mark outdated current classes, member variables, member methods or constructors. If the developer calls a method marked as outdated, the compiler warns during compilation.
  • @SuppressWarnings: Suppress warning annotations, which can be placed on classes and methods. The purpose of this annotation is to prevent the compiler from issuing certain warning messages.
  • @Repeatable: indicates that the marked annotation can be applied to the same declaration or type multiple times. This annotation was introduced by the Java 8 version.

3.2 @Override annotation

Marked on the member method, it is used to identify that the current method is to rewrite the parent class(parent interface) method. The compiler will check whether it complies with the rewriting rules when compiling the method. If it does not, the compiler will report an error.

Here to explain @Override annotation, there is a method in our Object base class is toString method, we usually rewrite this method in the entity class to achieve the effect of printing object information, this time will also find the rewritten toString method There is an @Override annotation above. As follows:

image-20200604203535421

So, we tried to change the rewritten toString method name and change the method name to toStrings. You will find an error during compilation! As follows:

image-20200604203645332

So what does this mean? This shows that this method is not a method of rewriting its parent class(Object). This is the role of @Override annotation.

3.3 @Deprecated annotation

Used to mark outdated current classes, member variables, member methods or constructors. If a developer calls a method marked as outdated, the compiler warns during compilation.

We need to simulate a scenario by explaining the @Deprecated annotation. Assuming that our company's product is currently version V1.0, it provides users with the function of the show1 method. At this time, we have expanded the function of the product's show1 method, intending to release V2.0 version. But do we need to abandon our version 1.0 products? In other words, will our V1.0 product features continue to be used by users? The answer must not be abandoned, because some users have been using the V1.0 version. If you abandon this version, you will lose a lot of users, so we can't abandon this version. At this time, after we extended the function, we released the V2.0 version. We only need to notify the user, that is, to inform the user that we have extended the function in the V2.0 version. You can let users choose their own version.

However, in addition to releasing the version to inform users, we also need to give hints on the functions of the original version. In the above simulation scenario, we need to add @Deprecated annotation above the show1 method to give hints. In this way, the user is also informed "This is the function of the old version, we do not recommend to continue to use the function of the old version", the meaning of this sentence is to give the user a hint. Users will also think "Oh, this version of this function is not easy to use, there must be a new version, and a better function. I will go to the official website to check and download the new version", and some users think "I understand Now, better functions have been updated, but I have enough features for this version, I don t need to download the new version again."

image-20200604205459205

So how do we check the function tips I mentioned above? At this time I need to create a method, then call the show1 method, and see how it prompts when calling.

image-20200604205659588

The picture has been posted. Do you find the similarities and differences between the new and old versions? Obviously, the hint in the method is to add a horizontal line to the called method name to cross out the method. This shows that the show1 method is outdated and is no longer recommended, we provide you with a better one.

In retrospect, there will be methods in our API that are outdated. For example, many of the methods in our Date class are outdated. As shown below:

image-20200604210154348

image-20200604210416762

As you can see, are many methods outdated? Is it annotated with @Deprecated? Come and follow my steps, I will show you.

image-20200604210515910

These methods in the Date class that we already know are outdated, if we use this method and execute the program. During the execution, you will be prompted that the method is outdated, but it is only a hint and does not affect your use of the method. as follows:

image-20200604221938895

OK! This is what the @Deprecated annotation does.

3.4 @SuppressWarnings annotation

Suppress warning annotations, which can be placed on classes and methods. The purpose of this annotation is to prevent the compiler from issuing certain warning messages. The annotation is a single-valued annotation. There is only one value parameter, which is a string array type. The parameter value is commonly used There are the following.

  • unchecked:unchecked conversion, if the collection does not specify the type, add elements
  • unused:unused variable
  • resource:There is a generic unspecified type
  • path:There is a non-existent path in the original file path in the class path
  • deprecation:some deprecated classes and methods are used
  • fallthrough:The switch statement is executed without break keyword
  • rawtypes:No generics are written, for example:List list = new ArrayList();
  • all:all types of warnings

Repression warning notes, as the name suggests, is the occurrence of repression warnings. We all know that in the process of writing Java code, there are many yellow warnings. But I don't know if your mentor has taught you, the programmer only needs to deal with the red error, and does not need to pay attention to the yellow warning. If your tutor has said this problem, there is a reason. Because in your learning stage, we can clearly handle the red error, which can reduce the memory content of your brain in the learning stage. If you have just joined the queue for learning Java, there are too many things that need to be remembered by the brain, that is, we don't need to remember other things at the moment, just remember the focus. As for the yellow warning, you will gradually understand it in your learning process, not by rote.

In order to explain the @SuppressWarnings annotation, we also use the previous example, because there is a yellow warning in that example.

image-20200604213625474

And every yellow warning will have a warning message. For example, the warning message in this picture tells you that the show2() method is not being used. In short, the show2 method you created, but you have not called this method in your code. In the future you will encounter various yellow warnings. Then, we can use different annotation parameters to suppress different annotations. However, in the parameters of the annotation, an all parameter is provided to suppress all types of warnings. And this note needs to be added above the class, and given all parameter, you can suppress all warnings. as follows:

image-20200604213943722

After we add the annotation and assign the all parameter, you will find that the warnings of the use method and the show2 method are gone. In fact, the warning of the Date package is still there, because we imported the Date package into this class, but we did not create a Date object. That is, it is not written in Date in the code, you will also find that the line is gray, which proves that we have not used any information that imports this package. In this case, we need to use this. To delete the contents of the guide package, use Ctrl + X to delete the packages that are not used. There is another way to modify the suppression warning annotation on the top of the package, but I think it is meaningless to press the annotation on a useless package, so we just delete it.

Then, we also saw the picture above, annotating that a warning message appeared on that line. This line means redundant warning suppression. This means that the suppression of the following warnings does not make sense to cause redundancy, but if we use this class and do something, the redundant warnings that suppress annotations will disappear. After all, we use this class. There will be no early field redundancy.

The above explanation @SuppressWarnings annotation is almost the same. OK, keep looking down. Continue to explain to everyone.

3.5 @Repeatable annotation

@Repeatable indicates that the marked annotation can be applied to the same declaration or type multiple times. This annotation was introduced by the Java 8 version. We know that annotations cannot be defined repeatedly. In fact, the annotation is a syntactic sugar, which can be used repeatedly, which is more suitable for our special scenarios.

First, we first create a reusable annotation.

package com.mylifes1110.anno;

import java.lang.annotation.Repeatable;

@Repeatable(Hour.class)
public @interface Hours {
double[]hours() default 0;
}

You will find that the annotation requires that the value passed in is a class object, such objects need to pass in another annotation, here is another class object of the annotation container. Let's create it.

package com.mylifes1110.anno;

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

//Container
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Hour {
Hours[]value();
}

In fact, the application of these two annotations is to encapsulate a common annotation with a reusable annotation to achieve the reuse of annotations. Finally, we create a test class, and then take you to take a look at the source code.

package com.mylifes1110.java;

import com.mylifes1110.anno.Hours;

@Hours(hours = 4)
@Hours(hours = 4.5)
@Hours(hours = 2)
public class Worker {
public static void main(String[]args) {
//Use the Hours annotation type to get the value array object in Worker
Hours[]hours = Worker.class.getAnnotationsByType(Hours.class);
//Traverse the array
for(Hours h:hours) {
System.out.println(h);
}
}
}

The test class is a worker test class. The worker uses annotations to record the working hours of morning, middle, and evening. The test results are as follows:

image-20200606183652359

Then we went into the source code to find out.

image-20200606183737877

We found that after entering the source code, we only saw an abstract method with a return value of class object. This also verifies that the annotation is just a syntactic sugar for repetitive annotations.

Four, annotation classification

4.1 Annotation classification

Annotations can be divided into three categories based on annotation parameters:

  • Markup annotations: annotations without parameters, only provide information for the program with its own presence or absence, such as @Override annotation, which has no parameters and is used to indicate that the current method is a rewrite method.
  • Single value annotations: There is only one parameter annotation. If the parameter name is value, then the parameter name can be omitted, such as @SuppressWarnings(value = "all"), which can be abbreviated as @SuppressWarnings("all").
  • Full note: Note with multiple parameters.

4.2 Tag annotations

Speaking of @Override annotation is a markup annotation, then we enter the source code of the annotation to check. Looking at the source code of the annotation from top to bottom, it is found that it inherits and imports java.lang.annotation.*, which means that the content of the package is used. Then there are two more unreadable annotations. In fact, the definition format of the annotation is publicly modified @Interface. Finally, I saw that the method body in the annotation does not have any parameters, that is, it only serves as a mark.

image-20200604215753302

4.3 Single value annotations

The @SuppressWarnings annotation we used above is a single value annotation. Let's go into its source code and see what happens. In fact, compared with the marked annotation, it has only one more value parameter, and this is the necessary condition for the single value annotation, that is, there is only one parameter. And when this parameter is value, we can omit value.

image-20200604220523115

4.4 Full note

The above two types of annotations are explained. As for the complete annotations, it will be more clear now. The method body is just having multiple parameters.

5. Custom annotations

5.1 Custom annotation format

Format: public @Interface annotation name {attribute list/no attribute}

Note: If there is no attribute in the annotation body, the essence is the mark annotation. But instead of the annotation annotation, the meta-annotation modified above is missing.

As follows, this is a note. But it is a bit different from jdk custom annotations. There are annotations above the jdk custom annotations to modify the annotation, and that annotation is called a meta annotation. I will explain the meta-notes in detail later.

image-20200606104149069

Here we really don't know what @Interface is, then we will decompile the custom annotation and take a look at the decompilation information. The decompilation operation is as follows:

image-20200606104818131

The contents of decompilation after decompilation are as follows:

public interface com.mylifes1110.anno.MyAnno extends java.lang.annotation.Annotation {
}

First of all, after reading the decompiled content, we can intuitively know that it is an interface, because the keyword behind its public modifier is interface.

Secondly, we found that the MyAnno interface inherits the Annotation interface under the java.lang.annotation package.

Therefore, we can know that the essence of the annotation is an interface, which inherits the Annotation interface by default.

Since it is the inherited Annotation interface, then we will go into this interface and see what it defines. The following is the interface content I extracted. We found that it seems very common, but in fact they are not very common, just to understand.

public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}

Finally, our annotations can also be written with attributes, its attributes are different from ordinary attributes, and its attributes are abstract methods. Since the annotation is also an interface, then we can say that what can be defined in the interface body, it can also be defined, and its modifier, like the interface, is also modified by public abstract by default.

The attributes in the annotation body are also required. The property requirements are as follows:

  • The return type of the attribute must be the following:

  • Basic data types

  • String type

  • Enumerated types

  • Notes

  • Arrays of the above types

  • Note: There can be no void return type and types other than the above types here

  • Defined attribute, you need to assign value to the attribute in the annotation when using it

  • If you use the default keyword to initialize the attribute when defining the attribute, you can leave the attribute unassigned when using annotations. It takes the default value. If the value is passed in again for it, then the original value is overwritten.

  • If only one attribute needs to be assigned, and the name of the attribute is value, then value can be omitted during assignment, and the value can be defined directly

  • When assigning an array, the value is stored using {}. If there is only one value in the array, you can omit {}.

5.2 Return value of custom annotation attribute

Since there are several types of attribute return values, then I will write these types here to demonstrate how to write them.

First, define an enumeration class and another annotation for backup.

package com.mylifes1110.enums;

public enum Lamp {
RED, GREEN, YELLOW
}

package com.mylifes1110.anno;

public @interface MyAnno2 {
}

Second, let's define the above types, as follows:

package com.mylifes1110.anno;

import com.mylifes1110.enums.Lamp;

public @interface MyAnno {
//Basic data type
int num();

//String type
String value();

//Enumeration type
Lamp lamp();

//Annotation type
MyAnno2 myAnno2();

//The above type of array
String[]values();
Lamp[]lamps();
MyAnno2[]myAnno2s();
int[]nums();
}

5.3 Custom annotation attribute assignment

Here we demonstrate, first, we use the annotation to demonstrate.

package com.mylifes1110.anno;

public @interface MyAnno {

//Basic data type
int num();

//String type
String value();

}

Then create a test class and write a note above the class. You will find that the parameters of the note will let you write these two parameters(int, String).

image-20200606113037920

At this time, it is done in this way. The format is:name = return value type parameter. as follows:

image-20200606113135414

As mentioned above, if you use the default keyword to give the property a default initialization value, you do not need to assign a value to its parameter. If you assign a value, you override the default initialization value.

image-20200606113518962

Of course, there is also a rule. If only one attribute needs to be assigned and the name of the attribute is value, then the value can be omitted when assigning, and the value can be directly defined. So, our num already has a default value, we can not pass it a value. We found that there is only one value attribute left in the attribute defined in the annotation, then we can demonstrate this rule.

image-20200606113849685

Here, I did not write the attribute name value, but directly assign value to the value. If I remove the default keyword modification of num, it means that num must be assigned when using this annotation, so can value be omitted? Let's take a look.

image-20200606114216801

The result is what we think, it reports an error and must let us assign a value to num. In fact, think about this rule is very easy to understand, define a value as value, you can omit the value name. If you define multiple values, they can omit the name and you can't distinguish which value is defined. The key is that there is an array, and multiple values are defined in the array, right?

5.4 Assignment of multiple return value types of custom annotations

Here we demonstrate how the above multiple return value types are assigned. Here we define these parameters to see how to assign values to attributes.

image-20200606114947483

num is an int basic data type, namely num = 1

value is a String type, ie value = "str"

lamp is an enumerated type, ie lamp = Lamp.RED

myAnno2 is an annotation type, that is, myAnno2 = @MyAnno2

values is an array of type String, ie values = {"s1", "s2", "s3"}

values is an array of type String, and there is only one value in the array, namely values = "s4"

Note: Values are separated by ,; arrays use {} to store values. If there is only one value in the array, you can omit {}; the enumeration type is enum Name. Enumeration value

image-20200606115023387

Yuan annotations

6.1 Meta-annotation classification

Meta annotations are annotations used to describe annotations. Meta annotations are generally used to limit the use scope, life cycle, etc. of custom annotations.

The four meta annotations are defined in the java.lang.annotation package in jdk, as follows:

Meta-annotation

description

@Target

Specify the scope of the modified annotation

@Retention

Specifies the life cycle of the modified annotation

@Documented

Notes that are modified can be documented with tools such as Javadoc

@Inherited

It can be inherited by subclasses when a modified annotation is specified to modify the program element

6.2 @Target

@Target specifies the scope of the modified annotation. Its scope can be found in the source code parameter value.

Attributes

description

CONSTRUCTOR

Used to describe the constructor

FIELD(commonly used)

Used to describe attributes

LOCAL_VARIABLE

Used to describe local variables

METHOD(commonly used)

Used to describe the method

PACKAGE

Used to describe the package

PARAMETER

Used to describe parameters

TYPE(commonly used)

Used to describe classes, interfaces(including annotation types) or enum declarations

ANNOTATION_TYPE

Used to describe the type of annotation

TYPE_USE

Used to describe the type of use

It can be seen that there is only one value attribute value in the annotation body, but its type is an ElementType array. Then we enter into this array to continue to view.

image-20200606140708009

Entering the array, you will find that he is an enumeration class, which defines the various attributes in the above table.

image-20200606141036340

After understanding the role and attribute value of @Target, let's use this annotation. First of all, we must first use the annotation to modify a custom annotation, define the specified role of the annotation on the class. as follows:

image-20200606142343441

And you observe the following test class, there is no error when we apply the annotation to the class. And when our annotations function in other places, they will report errors. This also shows that our @Target attribute plays a role.

Note: If we define multiple scopes, we can omit the parameter name, because the type is an array, although we can omit the name, we also need to use {} to store.

image-20200606142537664

6.3 @Retention

@Retention specifies the life cycle of the modified annotation

Attributes

description

RetentionPolicy.SOURCE

The annotations are only retained in the source code stage, and will be discarded and ignored when the compiler compiles.

RetentionPolicy.CLASS

The annotations are only retained until the class file is compiled, but the JVM is abandoned when loading the class file, that is, the class file will not be read at this stage.

RetentionPolicy.RUNTIME(commonly used)

Annotations can be retained until the program runs, it will be loaded into the JVM, so they can be obtained while the program is running.

Note: Our commonly used definition is RetentionPolicy.RUNTIME, because when we use reflection to achieve it, we need to get the class object from the JVM and manipulate the class object.

First of all, we have to understand the three life cycle stages of reflection. In this part, I also made a very detailed explanation in the "Java reflection mechanism". Interested friends can go and see the [Java reflection mechanism]I wrote( https://github.com/Ziphtracks/JavaLearningmanual/blob/master/docs/Java-Standard-Edition/Java%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6 . md), I believe you will gain something in it.

Here I emphasize again that these three life cycles are source code stage -> class class object stage -> Runtime runtime stage.

Then we go to the source code and see if these parameters are in the @Retention annotation.

image-20200606145014203

We see that the attribute in the annotation has only one value, and its type is a RetentionPolicy type. Let's enter this type to see what parameters are the same as the parameters in the table?

image-20200606145449931

As for how to use the annotation, it is actually the same, the usage is as follows:

image-20200606151837939

This proves that our annotations can be retained until the Runtime runtime phase, and most of our reflection is defined to the Runtime runtime phase, because we need to get the class object from the JVM and manipulate the class object.

6.4 @Documented

@Documented specifies that the modified annotation can be documented by tools such as Javadoc

@Documented annotation is relatively easy to understand, it is a markup annotation. Annotations marked with this annotation can be loaded into the document and displayed when the doc document is generated.

image-20200606152526551

Take the outdated Date method in the api for example. The getYear method in the Date display in the api is like this.

image-20200606153044390

As you can see, the annotation is displayed in the api, proving that the annotation is decorated and documented by @Documented annotation. Let's see if this annotation is modified by @Documented.

image-20200606153256793

Then, we found that the annotation was indeed documented. So the annotation will only be displayed in the API. If you don't believe it, you can use the javadoc command to generate a doc document and see if the annotation modified by the annotation exists.

As for the Javadoc documentation generation, I am in javadoc documentation generation has a detailed record in the article, you can refer to it, generate doc document to view.

6.5 @Inherited

@Inherited can be inherited by subclasses when the decorated annotation is used to decorate the program element

First enter the source code, we can also clearly know that the annotation is also a markup annotation. And it is also a documented annotation.

image-20200606154143241

Second, let's go to the custom annotation and mark it with @Inherited annotation.

image-20200606154343606

Demonstrating @Inherited annotation, I need to create two classes, and there is a layer of inheritance between the two classes. as follows:

image-20200606154216471

We marked the @MyAnno annotation in the Person class. Since the annotation is modified by the @Inherited annotation, we can conclude that the Student class inherited from the Person class is also marked by the @MyAnno annotation, if you want to get the value of the annotation , Sure to get the "1" of the annotated value on the parent class.

7. Use the reflection mechanism to parse the annotations

Custom annotation

package com.mylifes1110.anno;

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

/**
* @InterfaceName Sign
* @Description describes the name of the class and method to be executed
* @Author Ziph
* @Date 2020/6/6
* @Since 1.8
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sign {

String methodName();

String className();

}

Cat

package com.mylifes1110.java;

/**
* @ClassName Cat
* @Description class describing a cat
* @Author Ziph
* @Date 2020/6/6
* @Since 1.8
*/
public class Cat {

/\*
 \* @Description describes how a cat eats fish
 \* @Author Ziph
 \* @Date 2020/6/6
 \* @Param \[\]
 \* @return void
 \*/
public void eat() {
    System.out.println("Cat eats fish");
}

}

Ready, after the above code, we can start writing test classes that use reflection technology to parse annotations. as follows:

First, we first get the methodName and className parameters in the annotation by reflection.

package com.mylifes1110.java;

import com.mylifes1110.anno.Sign;

/**
* @ClassName SignTest
* @Description requires creating a cat object and executing the eat method in its class
* @Author Ziph
* @Date 2020/6/6
* @Since 1.8
*/
@Sign(className = "com.mylifes1110.java.Cat", methodName = "eat")
public class SignTest {

public static void main(String\[\]args) {
    //Get the class object of this class
    Class<SignTest> signTestClass = SignTest.class;
    //Get the annotation object in the class object
    //The principle is actually to generate a subclass implementation object of the annotation interface in memory
    Sign sign = signTestClass.getAnnotation(Sign.class);
    //Call the abstract method defined in the annotation object(the attribute in the annotation) to get the return value
    String className = sign.className();
    String methodName = sign.methodName();
    System.out.println(className);
    System.out.println(methodName);
}

}

The printing result at this time proves that we have successfully obtained the two parameters of the annotation.

image-20200606162810165

Note: When obtaining the annotation object in the class object, the principle is actually to generate a subclass implementation object of the annotation interface in memory and return the string content. as follows:

public class SignImpl implements Sign {

public String methodName() {
    return "eat";
}

public String className() {
    return "com.mylifes1110.java.Cat";
}

}

_ _

package com.mylifes1110.java;

import com.mylifes1110.anno.Sign;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* @ClassName SignTest
* @Description cat eat
* @Author Ziph
* @Date 2020/6/6
* @Since 1.8
*/
@Sign(className = "com.mylifes1110.java.Cat", methodName = "eat")
public class SignTest {

public static void main(String\[\]args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
    //      
    Class<SignTest> signTestClass = SignTest.class;
    //         
    //                        
    Sign sign = signTestClass.getAnnotation(Sign.class);
    //                          
    String className = sign.className();
    String methodName = sign.methodName();
    //className      
    Class<?> clazz = Class.forName(className);
    //  
    Object o = clazz.newInstance();
    //methodName       
    Method method = clazz.getMethod(methodName);
    //   
    method.invoke(o);
}

}

_ _

     eat                 

image-20200606163523994

JDBC

    JDBC        properties       JDBC                                                                                             

package com.mylifes1110.java.anno;

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

/**
* @InterfaceName DBInfo
* @Description
* @Author Ziph
* @Date 2020/6/6
* @Since 1.8
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBInfo {

String driver() default "com.mysql.jdbc.Driver";

String url() default "jdbc:mysql://localhost:3306/temp?useUnicode=true&characterEncoding=utf8";

String username() default "root";

String password() default "123456";

}

          properties          

package com.mylifes1110.java.utils;

import com.mylifes1110.java.anno.DBInfo;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
* @ClassName DBUtils
* @Description
* @Author Ziph
* @Date 2020/6/6
* @Since 1.8
*/
@DBInfo()
public class DBUtils {

private static final Properties PROPERTIES = new Properties();
private static String driver;
private static String url;
private static String username;
private static String password;

static {
    Class<DBUtils> dbUtilsClass = DBUtils.class;
    boolean annotationPresent = dbUtilsClass.isAnnotationPresent(DBInfo.class);
    if(annotationPresent) {
        /\*\*
         \* DBUilts   DBInfo         
         \*/
        DBInfo dbInfo = dbUtilsClass.getAnnotation(DBInfo.class);

//System.out.println(dbInfo);

        driver = dbInfo.driver();
        url = dbInfo.url();
        username = dbInfo.username();
        password = dbInfo.password();
    } else {
        InputStream inputStream = DBUtils.class.getResourceAsStream("db.properties");
        try {
            PROPERTIES.load(inputStream);
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
    try {
        Class.forName(driver);
    } catch(ClassNotFoundException e) {
        e.printStackTrace();
    }
}

public static Connection getConnection() {
    try {
        return DriverManager.getConnection(url, username, password);
    } catch(SQLException throwables) {
        throwables.printStackTrace();
    }
    return null;
}

public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
    try {
        if(resultSet != null) {
            resultSet.close();
            resultSet = null;
        }

        if(statement != null) {
            statement.close();
            statement = null;
        }
        if(connection != null) {
            connection.close();
            connection = null;
        }
    } catch(SQLException throwables) {
        throwables.printStackTrace();
    }
}

}

package com.mylifes1110.java.test;

import com.mylifes1110.java.utils.DBUtils;

import java.sql.Connection;

/**
* @ClassName GetConnectionDemo
* @Description
* @Author Ziph
* @Date 2020/6/6
* @Since 1.8
*/
public class GetConnectionDemo {

public static void main(String\[\]args) {
    Connection connection = DBUtils.getConnection();
    System.out.println(connection);
}

}

                       properties                 

image-20200606170207601

@MyTest

         Junit     @Test                                                       [  @MyTest       ](https://github.com/Ziphtracks/JavaLearningmanual/blob/master/docs/Java-Standard-Edition/Junit%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95.md#%E5%85%AB%E8%87%AA%E5%AE%9A%E4%B9%89mytest%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95)