整體Retrofit內容如下:
- 1、Retrofit解析1之前哨站——理解RESTful
- 2、Retrofit解析2之使用簡介
- 3、Retrofit解析3之反射
- 4、Retrofit解析4之注解
- 5、Retrofit解析5之代理設計模式
- 6、Retrofit解析6之面向接口編程
- 7、Retrofit解析7之相關類解析
- 8、Retrofit解析8之核心解析——ServiceMethod及注解1
- 9、Retrofit解析8之核心解析——ServiceMethod及注解2
- 10、Retrofit解析9之流程解析
- 11、Retrofit解析10之感謝
由于Retrofit里面大量的用到了注解,為了讓大家更好的學習Retrofit,特意準備了一篇Java注解,如果大家已經對Java注解已經很熟悉了,就略過,看下一篇文章
本篇文章主要講解
- 1、Java 注解技術基本概念
- 2、Java 元注解
- 3、標準注解/內建注解
- 4、自定義注解
- 5、注解處理器
- 6、注解思維導圖
- 7、注解原理
一、Java注解技術基本概念
(一) 什么是注解
Annotation是java 5開始引入的新特征。中文名稱一般叫注解。它提供了一種安全的類似于注釋的機制,用來將任何的信息或元數據(metadata)與程序元素(類、方法、成員變量等)進行關聯。
上面的類似官方的解釋,那我們再來通俗的解釋一下:
我們都知道在Java代碼中使用注解是為了提升代碼的可讀性,也就是說,注釋是給人看的(對編譯器來說是沒有意義上的)。注解可以看做注釋的"加強升級版",它可以向編譯器、虛擬機等解釋說明一些事情(也就是說它對編譯器等工具也是"可讀"的)。比如我們非常熟悉的@Overrider 注解,它的作用是告訴編譯器它所注解的方法是重寫父類中的方法,這樣編譯器就會檢查父類是否存在這個方法,以及這個方法的簽名與父類是否相同。
也就是說,注解是描述Java代碼的代碼,它能夠被編譯器解析,注解處理工具在運行時也能夠解釋注解。除了向編譯器等傳遞一些信息,我們也可以用注解生成代碼。比如我們可以用注解描述我們的意圖,然后讓注解解析工具來解析注解,以此來生成一些"模板化"的代碼。注解是一種"被動"的信息,必須有編譯器或虛擬機來"主動"解析它,它才能發揮自己的作用。
(二) 什么是元數據(metadata)
元數據由metadata翻譯來的,所謂元數據就是"關于數據的數據",更通俗的說就是描述數據的數據的,對數據及信息資源的描述性信息,比如一個文本文件,有創建時間、創建人、文件大小等數據,都是可以理解為是元數據。在java中,元數據以標簽的形式存在java代碼中,它的存在并不影響程序代碼的編譯和執行,通常它被用來生成其他的文件或運行時知道被運行代碼的描述信息。java代碼中的javadoc和注解都屬于元數據。
(三) 注解的前世今生
注解首先在第三版的Java Language Specification中被提出,并在Java 5中被實現。
(四)為什么要使用注解
- 1、在未使用Annotation之前(甚至是使用之后),一般使用XML來應用于元數據的描述。不是何時開始一些開發人員和架構師發現XML的維護原來越復雜和糟糕,他們希望使用一些和代碼緊密耦合的東西,而不是像XML一樣是松耦合的(在某些情況下甚至是完全分離的)代碼描述。如果你在百度或者google中搜索"xml vs annotations",就會看到關于這個話題的辯論。因為XML的配置就是為了分離代碼和配置而設置的。但是用Annotation(注解)還是XML各有利弊。(下面有舉例說明)
- 2、另外一個很重要的因素是Annotation注解定義一種標準的描述元數據的方式。在這之前,開發者通常使用他們自己的方式定義元數據。例如,使用標記interface,注釋,transient關鍵字等。每個程序員都用自己的方式定義元數據,而不像Annotation這種標準的方式。
下面我簡單舉例說明。
比如,你想為你的應用設置很多常量或參數,這種情況下,XML是一個很好的選擇,因為它不會與特定的代碼關聯。如果你想把某個方法聲明為服務,那么使用Annotation會更好一些,因為這種情況下需要注解和方法高度耦合一起。
因為XML是松耦合的,注解是緊耦合的,所以目前主流的框架將XML和Annotation兩種方式結合使用,平衡兩者之前的利弊。
在需要高度耦合的地方,Annotation注解比XML更容易維護,閱讀更方便
在需要松耦合的地方,使用XML更方便
在某個方法聲明為服務時,這種緊耦合的情況下,比較適合Annation注解。
(五)、注解的作用
Annotation 注解 通常被用以作以下目的:
- 1、編譯器指令
- 2、構建時指令
- 3、運行時指令
Java 內置了三種編譯器指令,Java注解可以應用于構建時,即當你構建你的項目時,構建的過程包括產生源代碼、編譯源代碼、產生xml文件,將編譯過的代碼或者文件打包進jar文件等。通常情況下,注解不會出現在編譯之后的Java代碼中,但是想要出現也是可以的。Java支持運行時注解。這些注解可以通過java反射訪問,運行時注解主要是提供給程序或者第三方API一些指令。
(六) 注解基礎
一個簡單的Java注解 類似于下面的這種 @Doctor ,"@" 符號告訴編譯器這是一個注解,跟在"@" 符號后面的是注解的名字,上述的例子中注解的名字是Doctor。
(七) 注解元素
Java 注解可以使用元素設置一些值,元素類似于屬性或者參數。下面是一個包含元素注解的例子
@Doctor (name = "張三")
上述注解的元素名稱是name,值是"張三",沒有元素的注解不需要括號。注解可以包含多個元素,下面就是包含多個元素的例子
@Doctor(name = "張三", sex= "男")
當注解只包含一個元素時,你可以省去寫元素的名字,直接賦值即可。下面的例子就是直接賦值。
@InsertNew("yes")
(八)注解使用
Annotation 注解可以在以下場合被使用到
- 類
- 接口
- 方法
- 方法參數
- 屬性
- 局部變量
二、元注解
(一) 什么是元注解
元注解,元注解就是負責注解其它注解.Java5.0定義了4個標準的meta-annotation類型,它們唄用來提供對其他annotation類型作說明。Java5.0定義的元注解:
- @Target
- @Retention
- @Documented
- @Inherited
這些類型和它們所支持的類在java.lang.annotation包中可以找到。下面我們來看一下每一個元注解的作用和說明
1、@Target
表示該注解可以用在什么地方,由ElementType枚舉定義
- CONSTRUCTOR:構造器的聲明
- FIELD:域聲明(包括enum實例)
- LOCAL_VARIABLE:布局變量聲明
- METHOD:方法聲明
- PACKAGE:包聲明
- PARAMETER:參數聲明
- TYPE:類、接口(包括注解類型)或enum聲明
- ANNOTATION_TYPE:注解聲明(應用于另一個注解上)
- TYPE_PARAMETER:類型參數聲明(1.8新加入)
- TYPE_USE:類型使用聲明(1.8新加入)
PS: 當注解未制定Target值時,此注解可以使用任何元素之上,就是上面的類型。
舉例如下:
@Target(ElementType.METHOD)
public @interface MethodInfo {
}
上面代碼中我們使用"@Target"元注解來說明MethodInfo這個注解只能應用于對方法進行注解。
2、@Retention
表示需要在什么級別保存該注解信息,由RetentionPolicy枚舉定義
- SOURCE:注解將編譯器丟棄(該類型的注解信息只會保留在源碼里,源碼經過編譯后,注解信息會被丟棄,不會保留在編譯好的class文件里)
- CLASS:注解在class中可用,但會被VM丟棄(該類型的注解信息會保留在源碼里和class文件里,在執行的時候,不會加載到虛擬機中(JVM)中)
- RUNTIME:VM將在運行期也保留注解信息,因此可以通過反射機制讀取注解信息(源碼、class文件和執行的時候都有注解的信息)
PS:當胡姐未定義Retention值時,默認值是CLASS
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
這表明@Override 注解只在源碼階段存在,javac在編譯過程中去掉該注解。
3、@Documented
表示注解會被包含在javaapi文檔中
當一個注解被@Documented元注解所修飾時,那么無論在哪里使用這個注解,都會被Javadoc工具文檔化。
舉例如下
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)public @interface Documented {
}
這個元注解唄@Documented修飾,表示它本身會被文檔化。@Retention注解的值RetentionPolicy.RUNTIME表示@Documented這個注解能保留在運行時;@Target元注解的值ElementType.ANNOTATION_TYPE表示@Documented這個注解只能夠來修飾注解類型
4、@Inherited
允許子類繼承父類的注解。
用于描述某個被標注的類型可被繼承的,如果一個使用了@Inherited修飾的annotation類型類型被用于一個class,則這個annotation將被用于該class類的子類。
表明被修飾的注解類型是自動繼承的。如果你想讓一個類和它的子類都包含某個注解,就可以使用@Inherited來修飾這個注解。也就是說,假設@Parent類是Child類的父類,那么我們若用被@Inherited元注解所修飾的某個注解對Parent類進行了修飾,則相當于Child類也被該注解所修飾了。這個元注解的定義如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)public @interface Inherited {
}
@Inherited
public @interface MyAnnotation {
}
@MyAnnotation
public class MySuperClass {
}
public class MySubClass extends MySuperClass {
}
上述代碼的大致意思是使用@Inherited修飾注解MyAnnotation使用MyAnnotation注解MySuperClass實現類MySubclass繼承自MySuperClass
當@Inherited annotation類型標注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查將展開工作:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。
三、標準注解/內建注解
Java本身內建了一些注解,用來為編譯器提供指令。如下:
- @Override
- @Deprecated
- @SuppressWarnings
下面讓我們詳細了解下三個標準注解/內建注解
1、@Override注解
@Override注解用來修飾對父類進行重寫的方法。如果一個并非重寫父類的方法使用這個注解,編譯器將提示錯誤。
實際上在子類中重寫父類或接口的方法,@Overrider并不是必須的。但是還是建議使用這個注解,在某些情況下,假設你修改了父類的方法的名字,那么之前重寫子類方法將不再屬于重寫,如果沒有@Override,你將不會覺察到這個子類的方法。有了這個注解修飾,編譯器則會提示你這些信息。
例子如下:
public class MySuperClass {
public void doTheThing() {
System.out.println("Do the thing");
}
}
public class MySubClass extends MySuperClass{
@Override
public void doTheThing() {
System.out.println("Do it differently");
}
}
2、@ Deprecated
@Deprecate 標記類、方法、屬性,如果上述三種元素不再使用,使用@Deprecated注解,建議用戶不再使用
如果代碼使用了@Deprecate 注解的類、方法或屬性,編譯器會進行警告。
舉例如下:
@Deprecated
public class MyComponent {
}
當我們使用@Deprecate注解后,建議配合使用對應的@deprecated JavaDoc 符號,并解釋說明為什么這個類,方法或屬性被棄用,已經替代方案是什么?如下:
@Deprecated
/**
@deprecated This class is full of bugs. Use MyNewComponent instead.
*/
public class MyComponent {
}
3、@SuppressWarnings
@SuppressWarnings 用來抑制編譯器生成警告信息??梢孕揎椀脑貫轭?,方法,方法參數,屬性,局部變量。
使用場景:當我們一個方法調用了棄用的方法或者進行不安全的類型轉換,編譯器會生成警告。我們可以為這個方法增加@SuppressWarnings
注解,來抑制編譯器生成警告。
PS:使用@SuppressWarnings注解,采用就近原則,比如一個方法出現警告,我們盡量使用@SuppressWarnings注解這個方法,而不是注解方法所在的類。雖然兩個都能抑制編譯器生成警告,但是范圍越小越好,因為范圍到了,不利于我們發現該類下其他方法的警告信息。
舉例如下:
@SuppressWarnings
public void methodWithWarning() {
}
四、自定義注解
1、注解格式
了解完系統注解之后,我們就可以自己定義注解了,通過上面的@Override的實例,不難看出定義注解的格式如下:
public @Interface 注解名{定義體}
PS:定義體就是方法的集合,每個方法實則是生命了一個配置參數,方法的名稱作為配置參數的名稱,方法的返回值類型就是配置參數的類型,和普通的方法不一樣,可以通過default關鍵字來聲明配置參數的默認值。
注意:
- 1、注解類型是通過"@interface"關鍵字定義的
- 2、此處只能使用public或者默認的default兩個權限修飾符
- 3、配置參數的類型只能使用基本類型(byte,boolean,char,short,int,long,float,double和String,Enum,Class,annotation)
- 4、對于只含有一個配置參數的注解,參數名建議設置中value,即方法名為value.
- 5、配置參數一旦設置,其參數值必須有確定的值,要不在使用注解的時候指定,要不在定義注解的時候使用default為其設置默認值,對于非基本類型的參數值來說,其不能為null。
2、創建自己的注解
在Java中,我們可以創建自己的注解,注解和類,接口文件一樣定義在自己的文件里面。如下:
@interface MyAnnotation {
String name();
int age();
String sex();
}
上述代碼定義了一個叫做MyAnnotation的注解,它有4個元素。再次強調一下,@Interface 這個關鍵字 用來告訴java編譯器這是一個注解。
應用舉例
@MyAnnotation(
name="張三",
age=18,
sex="男"
)
public class MyClass {
}
注意,我們需要為所有的注解元素設置值,一個都不能少。
3、自定義注解默認值
對于注解總的元素,我們可以為其設置默認值,使用方法如下:
@interface MyAnnotation {
String name();
int age();
String sex() default "男";
}
上述代碼,我們設置了sex元素的默認值為"男"。當我們在使用時,可以不設置sex的值,即讓value使用空字符串默認值。舉例如下;
@MyAnnotation(
name="Jakob",
age=37,
)
public class MyClass {
}
五、注解的原理
1、注解處理器
如果沒有用來讀取注解的方法和工作,那么注解也就不會比注釋更有用戶了,使用注解的過程中,很重要的一部分就是創建與使用注解處理器。Java SE 擴展了反射機制的API,以幫助程序員快速的構造自定義注解處理器。
2、注解處理器的分類
我們已經知道了如何自定義注解,當時想要注解發揮實際作用,需要我們為注解編寫響應的注解處理器,根據注解的特性,注解處理器可以分為運行時注解處理器和編譯時注解處理器。運行時注解處理器需要借助反射機制實現,而編譯時處理器則需要借助APT來實現。
無論是運行時注解處理器還是編譯時注解處理器,主要工作都是讀取注解及處理特定主機,從這個角度來看注解處理器還是非常容易理解的。
3、運行時注解處理器
熟悉Java反射機制的同學一定對java.lang.reflect包非常熟悉,該包中的所有API都支持讀取運行時Annotation的能力,即屬性為@Retention(RetentionPolicy.RUNTIME)的注解。
在Java.lang.reflect中中的AnnotatedElement接口是所有程序元素的(Class、Method)父接口,我們可以通過反射獲取到某個類的AnnotatedElement對象,進而可以通過該對象提供的方法訪問Annotation信息,常用的方法如下:
方法 | 含義 |
---|---|
< T extends Annotation > T getAnnotation(Class <T> annotationClass) | 表示返回該元素上存在的定制類型的注解 |
Annotation[] getAnnotations() | 返回該元素上存在的所有注解 |
default <T extends Annotation> T[] getAnnotationsByType(Class <T> annotationClass) | 返回該元素制定類型的注解 |
default <T extends Annotation> T getDeclaredAnnotation( Class <T> annotationClass) | 返回直接存在與該元素上的所有注解 |
default <T extends Annotation>T[] getDeclaredAnntationsByType(Class <T> annotationClass) | 返回直接存在該元素上某類型的注解 |
Annotation[] getDeclaredAnnotations() | 返回該元素上的所有注解 |
舉例說明
一個User實體類
public class User {
private int id;
private int age;
private String name;
@UserData(id=1,name="張三",age = 10)
public User() {
}
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
//...省略setter和getter方法
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
我們希望可以通過@UserData(id=1,name="張三",age = 10)這個注解,來為設置User實例的默認值。
自定義注解如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
public @interface UserData {
public int id() default 0;
public String name() default "";
public int age() default 0;
}
該注解類作用于構造方法,并在運行時存在,這樣我們就可以在運行時通過反射獲取注解進而為User實例設值,看看如何處理該注解
運行時注解處理器:
public class AnnotationProcessor {
public static void init(Object object) {
if (!(object instanceof User)) {
throw new IllegalArgumentException("[" + object.getClass().getSimpleName() + "] isn't type of User");
}
Constructor[] constructors = object.getClass().getDeclaredConstructors();
for (Constructor constructor : constructors) {
if (constructor.isAnnotationPresent(UserMeta.class)) {
UserMeta userFill = (UserMeta) constructor.getAnnotation(UserMeta.class);
int age = userFill.age();
int id = userFill.id();
String name = userFill.name();
((User) object).setAge(age);
((User) object).setId(id);
((User) object).setName(name);
}
}
}
}
測試代碼
public class Main {
public static void main(String[] args) {
User user = new User();
AnnotationProcessor.init(user);
System.out.println(user.toString());
}
}
運行測試代碼,便得到我們想要的結果:
User{id=1, age=10, name=’dong’}
這里通過反射獲取User類聲明的構造方法,并檢測是否使用了@UserData注解。然后從注解中獲取參數值并將其復賦值給User對象。
正如上面所說,運行時注解處理器的編寫本質上就是通過反射獲取注解信息,隨后進行其他操作。編譯一個運行時注解處理器就是那么簡答。運行時注解通常多用于參數配置模塊。
4、編譯時注解處理器
不同于運行時注解處理器,編寫編譯時注解處理器(Annotation Processor Tool)。
APT 用于編譯時期掃描和處理注解信息,一個特定的注解處理器可以以Java源文件或編譯后的class文件作為輸入,然后輸出另一些文件,而已是.java文件,也可以是.class文件,但通常我們輸出的是.java文件。(注意:并不是對源文件進行修改),這些java文件會和其他源文件一起被javac編譯。
你可能會很納悶,注解處理器是到底在什么階段介入的呢?好吧,其實是在javac開始編譯之前,這就是通常我們為什么愿意輸出.java文件的原因。
注解最早是在java 5引入的,主要包含APT和com.sum.mirror包中現相關mirror api,此時APT和javac是各自獨立的,但是從Java 6開始,注解處理器正式標準化,APT工具也被直接集成在javac當中。
編譯時注解處理器編譯一個注解時,主要分2步
- 1、 繼承AbstractProcessor,實現自己的注解處理器
- 2、注冊處理器,并打包成jar
舉例說明:
首先來看一下一個標準的注解處理器的格式:
public class MyAnnotationProcessor extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return super.getSupportedSourceVersion();
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
}
來簡單的了解下其中5個方法的作用
方法 | 作用 |
---|---|
init(ProcessingEnvironment processingEnv) | 該方法有注解處理器自動調用,其中ProcessingEnvironment類提供了很多有用的工具類:Filter,Types,Elements,Messager等 |
getSupportedAnnotationTypes() | 該方法返回字符串的集合表示該處理器用于處理那些注解 |
getSupportedSourceVersion() | 該方法用來指定支持的Java版本,一般來說我們都是支持到最新版本,因此直接返回SourceVersion.latestSupported()即可 |
process(Set annotations, RoundEnvironment roundEnv) | 該方法是注解處理器處理注解的主要地方,我們需要在這里寫掃描和處理注解的代碼,以及最終生成的java文件。其中需要深入的是RoundEnvironment類,該用于查找出程序元素上使用的注解 |
編寫一個注解處理器首先要對ProcessingEnvironment和RoundEnvironment非常熟悉。接下來我們來了解下這兩個類,先看下ProcessingEnvironment類:
public interface ProcessingEnvironment {
Map<String,String> getOptions();
//Messager用來報告錯誤,警告和其他提示信息
Messager getMessager();
//Filter用來創建新的源文件,class文件以及輔助文件
Filer getFiler();
//Elements中包含用于操作Element的工具方法
Elements getElementUtils();
//Types中包含用于操作TypeMirror的工具方法
Types getTypeUtils();
SourceVersion getSourceVersion();
Locale getLocale();
}
重點來認識一下Element,Types和Filer。Element(元素)是什么呢?
Element
element表示一個靜態的,語言級別的構件。而任何一個結構化文檔都可以看作是由不同的element組成的結構體,比如XML,JSON等。這里我們用XML來示例:
<root>
<child>
<subchild>.....</subchild>
</child>
</root>
這段xml中包含了三個元素:<root>、<child>、<subchild>到現在你已經明白元素是什么。對java源文件來說,他同樣是一種結構化文檔:
package com.demo; //PackageElement
public class Main{ //TypeElement
private int x; //VariableElement
private Main(){ //ExecuteableElement
}
private void print(String msg){ //其中的參數部分String msg TypeElement
}
}
對于java源文件來說,Element代表程序元素:包,類,方法都是一種程序元素。另外如果你對網頁解析工具jsoup熟悉,你會覺得操作此處的element是非常容易,關于jsoup不在本文講解之內。
接下來看看各種Element之間的關系圖,以便有個大概的了解
元素 | 含義 |
---|---|
VariableElement | 代表一個 字段, 枚舉常量, 方法或者構造方法的參數, 局部變量及 異常參數等元素 |
PackageElement | 代表包元素 |
TypeElement | 代表類或接口元素 |
ExecutableElement | 代碼方法,構造函數,類或接口的初始化代碼塊等元素,也包括注解類型元 |
TypeMirror、TypeElement、DeclaredType 這三個類我也簡單的介紹下:
- TypeMirror:代表Java語言中類型.Types包括基本類型,聲明類型,數組,類型變量和空類型。也代表通配類型參數,可執行文件的簽名和返回類型等.
- TypeElement 代表類或接口元素
- DeclaredType 代表類型或接口類型
簡單的來說,Element代表源代碼,TypeElement代表的是源碼中的類型元素,比如類,雖然我們可以從TypeElement中獲取類名,TypeElement中不包含類本身的信息,比如它的父類,要想獲取這信息需要借助TypeMirror,可以通過的Element中的asType()獲取元素對應的TypeMirror。
Filer
Filter 用于注解處理器中創新文件。
然后看一下RoundEnvironment這個類,這個類比較簡單
public interface RoundEnvironment {
boolean processingOver();
//上一輪注解處理器是否產生錯誤
boolean errorRaised();
//返回上一輪注解處理器生成的根元素
Set<? extends Element> getRootElements();
//返回包含指定注解類型的元素的集合
Set<? extends Element> getElementsAnnotatedWith(TypeElement a);
//返回包含指定注解類型的元素的集合
Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);
}
然后來看一下RoundEnvironment,這個類比較簡單,一筆帶過:
public interface RoundEnvironment { boolean processingOver(); //上一輪注解處理器是否產生錯誤 boolean errorRaised(); //返回上一輪注解處理器生成的根元素 Set<? extends Element> getRootElements(); //返回包含指定注解類型的元素的集合 Set<? extends Element> getElementsAnnotatedWith(TypeElement a); //返回包含指定注解類型的元素的集合 Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);}
Filer
Filer用于注解處理器中創建新文件。具體用法在下面示例會做演示.另外由于Filer用起來實在比較麻煩,后面我們會使用javapoet簡化我們的操作.
好了,關于AbstractProcessor中一些重要的知識點我們已經看完了.假設你現在已經編寫完一個注解處理器了,下面,要做什么呢? |
打包并注冊.
自定義的處理器如何才能生效那?為了讓Java編譯器找到自定義的注解處理器我們需要對其進行注冊和打包:自定義的處理器需要被達成一個jar,并且需要在jar包的META-INF/services路徑下中創建一個固定的文件
javax.annotation.processing.processor,在javax.annotation.processing.Processor文件中需要填寫自定義處理器的完整路徑名,有幾個處理器就要填寫幾個
從Java 6之后,我們只需要將打開的jar防止到項目的buildpath下即可,javac在運行的過程會自動檢查javax.annotation.processing.Processor注冊的注解處理器,并將其注冊上。而Java 5需要單獨使用APT工具。
最終我們需要獲得一個包含注解處理器的代碼的jar包
六、注解基礎知識思維導圖
最后借用下別人的Java注解的基礎知識點導圖