在Spring 2.0及早期時代,Java 還沒引入註解,這個時候如果我們要在 Spring 中宣告一個 Bean,我們只能通過 XML 設定的方式,Web專案開發都是通過組態檔 xml來實現 Bean 的依賴注入,有多少個Bean,就在xml設定中加多少個,這樣一來在 Bean 的數量越來越多的時候,xml的設定也就會越來越複雜,顯得格外的冗餘,Spring 2.0 在xml組態檔上做了一定的優化,讓設定看起來越來越簡單。
而在後來的 Spring 3.0 時代,可以使用 Spring 提供的 Java 註解來取代曾經 xml 設定上的所產生的問題,Spring 使得專案開發設定變得簡單了許多
.註解其實就是程式碼裡的特殊標記 ,這些標記可以在編譯,類載入,執行時被讀取,並執行相應的處理。通過使用註解,程式設計師可以在不改變原有邏輯的情況下 ,在原始檔中嵌入一些補充資訊。程式碼分析工具,開發工具和部署工具可以通過這些補充資訊進行驗證或者進行部署
1,註解的出現極大的簡化了jdk1.5之前 使用xml設定的方式,代替JavaEE舊版中所遺留的繁冗程式碼和XML設定等
2,生產檔案註解,標明該模組類開發者,模組版本等資訊。
3,在編譯時進行格式檢查(Jdk內建的三個基本註解)
4,跟蹤程式碼依賴性,實現替代組態檔等功能
範例
xml設定方式
public class DemoService{
}
<bean id="demoService" class="com.lulu.DemoService"/>
註解設定方式
@Service
public class DemoService{
}
未來的開發模式都是基於註解的,JPA是基於註解的,Spring2.5以上是基於註解的,現在的springboot是完全註解開發,註解是一種趨勢,一定程度上可以說:框架=註解+反射+設計模式。
1:
在定義註解之前我們可以看看註解的原始碼是怎樣定義的
我們可以通過idea的快捷鍵選中註解 按住Crtl同時點選滑鼠左鍵檢視註解原始碼
如 選中select()上的 @Override
@Override
public List<Admin> select() {
return adminMapper.select();
}
}
2:
然後我們就看到了原始碼對@Override的定義,可以發現這和介面的定義很像,都有通過interface進行宣告,只不過interface多了一個@
還有兩個對註解的註解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
3:
然後我們可以參照此註解自定義註解,首先使用@interface關鍵字(自定義的註解自動繼承了java.lang.annotation.Annotation介面),我們可以給該註解加入一個成員引數屬性 value ,注意,雖然value有一對括號,和類,介面的方法定義很像 但它是註解的屬性不是方法
/**
* @author Tony-wang
* @create 2020-09-17-16:05
*/
public @interface MyAnnotation {
String value()
}
4:
然後我們就可以在其它類或方法上使用自定義註解了
注意 宣告註解成員後 如果沒有指定預設值default就要 在使用註解時 顯示的賦值 ,如果不宣告內部成員,那麼該註解僅起到一個標識作用,如@Override就沒有內部成員
@MyAnnotation("hello")
public class Person{
元註解 是jdk中修飾其他註解的註解,jdk1.5中提供了4種標準的meta-annotation型別 分別是 Retention Target Document Inherited
Retention:只能用於修飾一個Annotation定義,用於指定該Annotation的生命週期,該元註解包含一個RetentionPolicy型別的成員變數,使用@Rentention必須為該value賦值
RetentionPolicy有三個狀態
RetentionPolicy.SOURCE:在原始檔中有效(編譯器直接丟棄這種策略的註釋)
RetentionPolicy.CLASS:在class檔案中有效,當執行java程式時,jvm不會保留註釋,這是預設值
RetentionPolicy.RUNTIME:在執行時有效(即執行中保留),當執行java程式時,jvm會保留註釋,程式可以通過反射獲取該註釋 *
Target 用於修飾該註解可以在哪些地方進行使用 指定類 中使用還是介面使用還是區域性變數進行使用
如 該註解就只能在屬性和方法中使用
@Target({FIELD,METHOD})//表示該註解只能使用在屬性和方法上
@Retention(RetentionPolicy.RUNTIME)//執行時有效,被jvm類載入器載入到記憶體後 可以通過反射獲取註解資訊
public @ interface MyAnnotation{
Document :用於指定該註解會被javadoc 工具提取為檔案(很少用)
Inherited:被它修飾的註解具有基礎性(很少用)
元註解@Repeatable
元註解@Repeatable是JDK1.8新加入的,它表示在同一個位置重複相同的註解。在沒有該註解前,一般是無法在同一個型別上使用相同的註解的
//Java8前無法這樣使用
@FilterPath("/web/update")
@FilterPath("/web/add")
public class A {}
但在Java8新增了@Repeatable註解後就可以採用如下的方式定義並使用了
//使用Java1.8新增@Repeatable元註解
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(FilterPaths.class)//引數指明接收的註解class
public @interface FilterPath {
String value();
}
//使用案例
@FilterPath("/web/add")
@FilterPath("/web/delete")
class AA{ }
JDK1.8新增兩個列舉元
在Java8中 ElementType 新增兩個列舉元,TYPE_PARAMETER 和 TYPE_USE ,在Java1.8前註解只能標註在一個宣告(如欄位、類、方法)上,Java8後,新增的TYPE_PARAMETER可以用於標註型別引數,而TYPE_USE則可以用於標註任意型別(不包括class)。如下TYPE_USE修飾泛型型別,異常型別,強轉型別所示
@Target({FIELD,METHOD,TYPE_PARAMETER,TYPE_USE})//
@Retention(RetentionPolicy.RUNTIME)//執行時有效,被jvm類載入器載入到記憶體後 可以通過反射獲取註解資訊
public @ interface MyAnnotation{
string value() default "HEELO 靚仔!"
}
class Generic<@MyAnnotation T>{ //註解修飾泛型型別
public void show() throws @MyAnnotation RuntimeException{//註解修飾異常型別
ArrayList<@MyAnnotation String> list = new ArrayList<>();
int num = (@MyAnnotation int ) 10L;//對強轉型別進行修飾
}