1、定義:
註解(也被稱爲元數據)爲咱們在代碼中添加信息提供了一種形式化的方法,使咱們能夠在稍後某個時刻很是方便地使用這些數據。html
2、做用:
①編寫文檔 :經過代碼裏標識的元數據生成文檔【生成文檔doc文檔 @param @return @see @exception @version @author @since】
②編譯檢查 :經過代碼裏標識的元數據讓編譯器可以實現基本的編譯檢查【@Override @Deprecated [ˈdeprəkeɪtɪd] @SuppressWarnings】
③運行時分析:經過代碼裏標識的元數據對代碼進行分析【使用反射解析註解】java
3、註解與註釋區別:
註釋:是對代碼的描述、說明, 編譯器在編譯生成字節碼文件時通常會自動忽略註釋,在運行時沒法獲取。
註解:能夠存在於源文件、class文件、以及程序運行時,是代碼的一部分。spring
4、Java內置三種標準註解:
① @Deprecated
註解爲不建議使用,能夠用在 方法和類上。
基本上這種方法和類都是由於升級或性能上面的一些緣由廢棄不建議使用,可是爲了兼容或其餘緣由,還必須保留。
因此就打上這個註解。
在Java 自己的API中就有不少這樣的例子, 方法打上了這個註解,進到Source code 會看到替代的新的方法是哪一個。
在eclipse 中編寫code時,添加此註解的方法在聲明和調用的地方都會加上刪除線。
② @Override
覆蓋超類中的方法。
若是不當心拼寫錯誤,或者方法簽名對不上被覆蓋的方法,編譯器就會發出錯誤提示信息。
③ @SuppressWarnings
忽略警告。
若是你的code在轉型或其餘的部分有一些警告的話,可是你又想忽略這些警告,就可使用這個註解了。
1) deprecation 使用了不同意使用的類或方法時的警告
2) unchecked 執行了未檢查的轉換時警告
3) fallthrough 當使用switch操做時case後未加入break操做,而致使程序繼續執行其餘case語句時出現的警告
4) path 當設置一個錯誤的類路徑、源文件路徑時出現的警告
5) serial 當在可序列化的類上缺乏serialVersionUID定義時的警告
6) fianally 任何finally子句不能正常完成時警告
7) all 關於以上全部狀況的警告json
5、Java內置四種元註解:
元註解的做用就是負責註解其餘註解,在自定義註解的時候常用。
Java5.0定義了4個標準的meta-annotation類型,它們被用來提供對其它 annotation類型做說明。Java5.0定義的元註解:
1.@Target : 描述註解修飾對象範圍
2.@Retention : 描述註解存在的生命週期
3.@Documented : 在JavaDoc中,包含此註解信息
4. @Inhretied : 容許子類繼承父類中的註解數組
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value(); }
@Target:
@Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
做用:用於描述註解的使用範圍(即:被描述的註解能夠用在什麼地方)
取值(ElementType)有:
1.CONSTRUCTOR:用於描述構造器
2.FIELD:用於描述域
3.LOCAL_VARIABLE:用於描述局部變量
4.METHOD:用於描述方法
5.PACKAGE:用於描述包
6.PARAMETER:用於描述參數
7.TYPE:用於描述類、接口(包括註解類型) 或enum聲明
8.ANNOTATION_TYPE :用於描述註解app
@Retention:
@Retention定義了該Annotation被保留的時間長短:某些Annotation僅出如今源代碼中,而被編譯器丟棄;而另外一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另外一些在class被裝載時將被讀取(請注意並不影響class的執行,由於Annotation與class在使用上是被分離的)。使用這個meta-Annotation能夠對 Annotation的「生命週期」限制。
做用:表示須要在什麼級別保存該註釋信息,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在運行時有效(即運行時保留)eclipse
@Documented:
@Documented用於描述其它類型的annotation應該被做爲被標註的程序成員的公共API,所以能夠被例如javadoc此類的工具文檔化。Documented是一個標記註解,沒有成員。ide
@Inherited:
@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承的。若是一個使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。
注意:@Inherited annotation類型是被標註過的class的子類所繼承。類並不從它所實現的接口繼承annotation,方法並不從它所重載的方法繼承annotation。
當@Inherited annotation類型標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API加強了這種繼承性。若是咱們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查將展開工做:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。工具
使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其餘細節。在定義註解時,不能繼承其餘的註解或接口。@interface用來聲明一個註解,其中的每個方法其實是聲明瞭一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)。能夠經過default來聲明參數的默認值。post
定義註解格式:
public @interface 註解名 {定義體}
註解參數的可支持數據類型:
1.全部基本數據類型(int,float,boolean,byte,double,char,long,short)
2.String類型
3.Class類型
4.enum類型
5.Annotation類型
6.以上全部類型的數組
Annotation類型裏面的參數該怎麼設定:
第一,只能用public或默認(default)這兩個訪問權修飾.例如,String value();這裏把方法設爲defaul默認類型;
第二,參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和 String,Enum,Class,annotations等數據類型,以及這一些類型的數組.例如,String value();這裏的參數成員就爲String;
第三,若是隻有一個參數成員,最好把參數名稱設爲"value",後加小括號.
1. 定義英雄註解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Hero { //戰士、巫師、刺客 public enum HeroType{WARRIOR, WIZARD, ASSASSIN}; HeroType heroType() default HeroType.WARRIOR; }
2. 定義技能註解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Skill { //普通技能、終極技能 public enum SkillType{NORNAL, FINAL}; String skillDesc() default ""; SkillType skillType() default SkillType.NORNAL; }
3. 定義抽象英雄類
public abstract class AbstractHero { //英雄名稱 private String heroName; AbstractHero(String heroName){ this.heroName = heroName; } //一技能 public abstract void Q(); //二技能 public abstract void W(); //三技能 public abstract void E(); //終極技能 public abstract void R(); public String getHeroName() { return heroName; } public void setHeroName(String heroName) { this.heroName = heroName; } }
4. 定義兩個英雄類
@Hero(heroType = HeroType.WARRIOR) public class Tiny extends AbstractHero{ public Tiny() { super("小小"); } @Skill(skillDesc = "形成1.2秒眩暈") @Override public void Q() { System.out.println("山崩"); } @Skill(skillDesc = "起飛") @Override public void W() { System.out.println(this.getHeroName() + "釋放了:投擲"); } @Skill(skillDesc = "抗揍神技") @Override public void E() { System.out.println(this.getHeroName() + "釋放了:崎嶇外表"); } @Skill(skillType = SkillType.FINAL , skillDesc = "攻速減半") @Override public void R() { System.out.println(this.getHeroName() + "釋放了:長大"); } }
@Hero(heroType = HeroType.WIZARD) public class Ezalor extends AbstractHero{ public Ezalor() { super("甘道夫"); } @Skill(skillDesc = "衝擊波衝擊波") @Override public void Q() { System.out.println(this.getHeroName() + "釋放了:衝擊波"); } @Skill(skillDesc = "法力流失") @Override public void W() { System.out.println(this.getHeroName() + "釋放了:法力流失"); } @Skill(skillDesc = "查克拉魔法") @Override public void E() { System.out.println(this.getHeroName() + "釋放了:查克拉魔法"); } @Skill(skillType = SkillType.FINAL , skillDesc = "光之守衛") @Override public void R() { System.out.println(this.getHeroName() + "釋放了:光之守衛"); } }
5. 定義測試類
public class HeroResover { public static void main(String[] args){ createOnlyWarrior(); createOnlyWarriorFinalSkill(); } /** * 建立hero包中的全部戰士,並釋放Q技能 */ private static void createOnlyWarrior(){ String basePackage = "com.hand.jeb.class1.heros"; //獲取hero包下全部類 List<String> clazzNameList = PackageUtil.getClassName(basePackage); for(String clazzName : clazzNameList){ System.out.println(clazzName); try { Class<?> heroClazz = Class.forName(clazzName); //獲取Hero註解 Hero heroAnnotation = heroClazz.getAnnotation(Hero.class); //若是類具備 @Hero註解,而且HeroType爲WARRIOR if(heroAnnotation != null && HeroType.WARRIOR.equals(heroAnnotation.heroType())){ AbstractHero warrior = (AbstractHero) heroClazz.newInstance(); warrior.Q(); } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } } /** * 建立hero包中的全部戰士,並釋放終極技能 */ private static void createOnlyWarriorFinalSkill(){ String basePackage = "com.hand.jeb.class1.heros"; //獲取hero包下全部類 List<String> clazzNameList = PackageUtil.getClassName(basePackage); for(String clazzName : clazzNameList){ System.out.println(clazzName); try { Class<?> heroClazz = Class.forName(clazzName); //獲取Hero註解 Hero heroAnnotation = heroClazz.getAnnotation(Hero.class); if(heroAnnotation != null && HeroType.WARRIOR.equals(heroAnnotation.heroType())){ AbstractHero warrior = (AbstractHero) heroClazz.newInstance(); Method[] methods = heroClazz.getMethods(); for(Method method : methods){ //System.out.println(method.getName()); Skill skillAnnotation = method.getAnnotation(Skill.class); //若是方法上有終極技能註解則釋放 if(skillAnnotation != null && SkillType.FINAL.equals(skillAnnotation.skillType())){ method.invoke(warrior); } } } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } } }
將上面的小例子做出修改,在英雄類上增長@Compent註解,並在Spring配置文件中增長包掃描
<context:component-scan base-package="com.hand.jeb.class1.heros"/>
建立Spring測試類
public class HeroSpringResover { private static ApplicationContext ctx = null; private static ApplicationContext getContextInstance(){ if(ctx != null) return ctx; else return new GenericXmlApplicationContext("classpath:/spring/applicationContext.xml"); } public static void main(String[] args) { createOnlyWarrior(); } /** * 建立hero包中的全部戰士,並釋放Q技能 */ private static void createOnlyWarrior(){ String basePackage = "com.hand.jeb.class1.heros"; //獲取hero包下全部類 List<String> clazzNameList = PackageUtil.getClassName(basePackage); for(String clazzName : clazzNameList){ System.out.println(clazzName); try { Class<?> heroClazz = Class.forName(clazzName); //獲取Hero註解 Hero heroAnnotation = heroClazz.getAnnotation(Hero.class); //若是類具備 @Hero註解,而且HeroType爲WARRIOR if(heroAnnotation != null && HeroType.WARRIOR.equals(heroAnnotation.heroType())){ //AbstractHero warrior = (AbstractHero) heroClazz.newInstance(); //使用Spring獲取bean AbstractHero warrior = (AbstractHero) getContextInstance().getBean(heroClazz); warrior.Q(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } }
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { String value() default ""; }
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { String value() default ""; }
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Repository { String value() default ""; }
@Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean纔會按照類型來裝配注入
@Autowired默認是按照類型裝配注入的,若是想按照名稱來轉配注入,則須要結合@Qualifier一塊兒使用
@Resource註解是由J2EE提供,而@Autowired是由Spring提供,故減小系統對spring的依賴建議使用@Resource的方式
@Resource和@Autowired均可以書寫標註在字段或者該字段的setter方法之上
<bean id="heroDao" class="com.hand.jeb.HeroImpl"></bean>
@Resource(name="heroDao") private IHero hero; @Autowired //若是有多個類實現了同一個接口,須要使用Qualifier區分 @Qualifier("heroDao") private IHero hero;
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { // @AliasFor註解可用於聲明一雙別名屬性,來給註解的屬性起別名 @AliasFor("transactionManager") String value() default ""; @AliasFor("value") // 可選的限定描述符,指定使用的事務管理器,同value String transactionManager() default ""; //可選的事務傳播行爲設置 Propagation propagation() default Propagation.REQUIRED; //可選的事務隔離級別設置 Isolation isolation() default Isolation.DEFAULT; //事務超時時間 int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; //讀寫或只讀事務,默認讀寫 boolean readOnly() default false; //致使事務回滾的異常類數組 Class<? extends Throwable>[] rollbackFor() default {}; //致使事務回滾的異常類名稱數組 String[] rollbackForClassName() default {}; //不會致使事務回滾的異常類數組 Class<? extends Throwable>[] noRollbackFor() default {}; //不會致使事務回滾的異常類名稱數組 String[] noRollbackForClassName() default {}; }
Propagation : 事務傳播行爲
事務傳播行爲類型 |
說明 |
PROPAGATION_REQUIRED |
若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。這是最多見的選擇。 |
PROPAGATION_SUPPORTS |
支持當前事務,若是當前沒有事務,就以非事務方式執行。 |
PROPAGATION_MANDATORY |
使用當前的事務,若是當前沒有事務,就拋出異常。 |
PROPAGATION_REQUIRES_NEW |
新建事務,若是當前存在事務,把當前事務掛起。 |
PROPAGATION_NOT_SUPPORTED |
以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。 |
PROPAGATION_NEVER |
以非事務方式執行,若是當前存在事務,則拋出異常。 |
PROPAGATION_NESTED |
若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行與PROPAGATION_REQUIRED類 似的操做。 |
Isolation: 事務隔離級別
事務隔離級別 |
說明 |
READ_UNCOMMITTED |
讀取未提交數據(會出現髒讀, 不可重複讀) 基本不使用。 |
READ_COMMITTED |
讀取已提交數據(會出現不可重複讀和幻讀) |
REPEATABLE_READ |
可重複讀(會出現幻讀) |
SERIALIZABLE |
串行化 |
@RequestMapping :SpringMVC分發請求映射,屬性 method = RequestMethod.POST/ RequestMethod.GET能夠限制請求類型
@RequestBody :
該註解用於讀取Request請求的body部分數據,使用系統默認配置的HttpMessageConverter進行解析,而後把相應的數據綁定到要返回的對象上;再把HttpMessageConverter返回的對象數據綁定到 controller中方法的參數上。
使用時機:
A) GET、POST方式提時, 根據request header Content-Type的值來判斷:
B) PUT方式提交時, 根據request header Content-Type的值來判斷:
說明:request的body部分的數據編碼格式由header部分的Content-Type指定;
@ResponseBody
做用:
該註解用於將Controller的方法返回的對象,經過適當的HttpMessageConverter轉換爲指定格式後,寫入到Response對象的body數據區。
使用時機:
返回的數據不是html標籤的頁面,而是其餘某種格式的數據時(如json、xml等)使用
@RequestParam
做用:
A) 經常使用來處理簡單類型的綁定,經過Request.getParameter() 獲取的String可直接轉換爲簡單類型的狀況( String--> 簡單類型的轉換操做由ConversionService配置的轉換器來完成);由於使用request.getParameter()方式獲取參數,因此能夠處理get 方式中queryString的值,也能夠處理post方式中 body data的值;
B)用來處理Content-Type: 爲 application/x-www-form-urlencoded
編碼的內容,提交方式GET、POST;
C) 該註解有兩個屬性: value、required; value用來指定要傳入值的id名稱,required用來指示參數是否必須綁定
@PathVariable
做用:
當使用@RequestMapping URI template 樣式映射時, 即 someUrl/{paramId}, 這時的paramId可經過 @Pathvariable註解綁定它傳過來的值到方法的參數上。