Spring中的註解大概能夠分爲兩大類:java
1)spring的bean容器相關的註解,或者說bean工廠相關的註解;spring
2)springmvc相關的註解。數組
spring的bean容器相關的註解,前後有:@Required, @Autowired, @PostConstruct, @PreDestory,還有Spring3.0開始支持的JSR-330標準javax.inject.*中的註解(@Inject, @Named, @Qualifier, @Provider, @Scope, @Singleton).session
springmvc相關的註解有:@Controller, @RequestMapping, @RequestParam, @ResponseBody等等。mvc
要理解Spring中的註解,先要理解Java中的註解。app
Java中1.5中開始引入註解,Java中引入的註解以下less
咱們最熟悉的應該是:@Override, 它的定義以下:ide
/** * Indicates that a method declaration is intended to override a * method declaration in a supertype. If a method is annotated with * this annotation type compilers are required to generate an error * message unless at least one of the following conditions hold: * * <ul><li> * The method does override or implement a method declared in a * supertype. * </li><li> * The method has a signature that is override-equivalent to that of * any public method declared in {@linkplain Object}. * </li></ul> * * @author Peter von der Ahé * @author Joshua Bloch * @jls 9.6.1.4 @Override * @since 1.5 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
從註釋,咱們能夠看出,@Override的做用是,提示編譯器,使用了@Override註解的方法必須override父類或者java.lang.Object中的一個同名方法。咱們看到@Override的定義中使用到了 @Target, @Retention,它們就是所謂的「元註解」——就是定義註解的註解,或者說註解註解的註解(暈了...)。函數
/** * Indicates how long annotations with the annotated type are to * be retained. If no Retention annotation is present on * an annotation type declaration, the retention policy defaults to * {@code RetentionPolicy.CLASS}. * * <p>A Retention meta-annotation has effect only if the * meta-annotated type is used directly for annotation. It has no * effect if the meta-annotated type is used as a member type in * another annotation type. * * @author Joshua Bloch * @since 1.5 * @jls 9.6.3.2 @Retention */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }
@Retention用於提示註解被保留多長時間,有三種取值:工具
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
RetentionPolicy.SOURCE 保留在源碼級別,被編譯器拋棄(@Override就是此類);
RetentionPolicy.CLASS被編譯器保留在編譯後的類文件級別,可是被虛擬機丟棄;
RetentionPolicy.RUNTIME保留至運行時,能夠被反射讀取;
/** * Indicates the contexts in which an annotation type is applicable. The * declaration contexts and type contexts in which an annotation type may be * applicable are specified in JLS 9.6.4.1, and denoted in source code by enum * constants of {@link ElementType java.lang.annotation.ElementType}. * * <p>If an {@code @Target} meta-annotation is not present on an annotation type * {@code T} , then an annotation of type {@code T} may be written as a * modifier for any declaration except a type parameter declaration. * * <p>If an {@code @Target} meta-annotation is present, the compiler will enforce * the usage restrictions indicated by {@code ElementType} * enum constants, in line with JLS 9.7.4. * * <p>For example, this {@code @Target} meta-annotation indicates that the * declared type is itself a meta-annotation type. It can only be used on * annotation type declarations: * <pre> * @Target(ElementType.ANNOTATION_TYPE) * public @interface MetaAnnotationType { * ... * } * </pre> * * <p>This {@code @Target} meta-annotation indicates that the declared type is * intended solely for use as a member type in complex annotation type * declarations. It cannot be used to annotate anything directly: * <pre> * @Target({}) * public @interface MemberType { * ... * } * </pre> * * <p>It is a compile-time error for a single {@code ElementType} constant to * appear more than once in an {@code @Target} annotation. For example, the * following {@code @Target} meta-annotation is illegal: * <pre> * @Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD}) * public @interface Bogus { * ... * } * </pre> * * @since 1.5 * @jls 9.6.4.1 @Target * @jls 9.7.4 Where Annotations May Appear */ @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用於提示該註解使用的地方,取值有:
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ //類,接口,註解,enum TYPE, /** Field declaration (includes enum constants) */ //屬性域 FIELD, /** Method declaration */ //方法 METHOD, /** Formal parameter declaration */ //參數,1.8後用TYPE_PARAMETER PARAMETER, /** Constructor declaration */ //構造函數 CONSTRUCTOR, /** Local variable declaration */ //局部變量 LOCAL_VARIABLE, /** Annotation type declaration */ //註解類型 ANNOTATION_TYPE, /** Package declaration */ //包 PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE }
因此:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
表示 @Override 只能使用在方法上,保留在源碼級別,被編譯器處理,而後拋棄掉。
還有一個常用的元註解 @Documented :
/** * Indicates that annotations with a type are to be documented by javadoc * and similar tools by default. This type should be used to annotate the * declarations of types whose annotations affect the use of annotated * elements by their clients. If a type declaration is annotated with * Documented, its annotations become part of the public API * of the annotated elements. * * @author Joshua Bloch * @since 1.5 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
表示註解是否能被 javadoc 處理並保留在文檔中。
/** * Indicates that an annotation type is automatically inherited. If * an Inherited meta-annotation is present on an annotation type * declaration, and the user queries the annotation type on a class * declaration, and the class declaration has no annotation for this type, * then the class's superclass will automatically be queried for the * annotation type. This process will be repeated until an annotation for this * type is found, or the top of the class hierarchy (Object) * is reached. If no superclass has an annotation for this type, then * the query will indicate that the class in question has no such annotation. * * <p>Note that this meta-annotation type has no effect if the annotated * type is used to annotate anything other than a class. Note also * that this meta-annotation only causes annotations to be inherited * from superclasses; annotations on implemented interfaces have no * effect. * * @author Joshua Bloch * @since 1.5 * @jls 9.6.3.3 @Inherited */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
指示註解類型被自動繼承。若是在註解類型聲明中存在 Inherited 元註解,而且用戶在某一類聲明中查詢該註解類型,同時該類聲明中沒有此類型的註解,則將在該類的超類中自動查詢該註解類型。此過程會重複進行,直到找到此類型的註解或到達了該類層次結構的頂層 (Object) 爲止。若是沒有超類具備該類型的註解,則查詢將指示當前類沒有這樣的註解。
注意,若是使用註解類型註解類之外的任何事物,此元註解類型都是無效的。還要注意,此元註解僅促成從超類繼承註解;對已實現接口的註解無效。
即一個類中,沒有@Father的註解,可是這個類的父類有@Father註解,且@Father註解被@Inherited註解,則在使用反射獲取子類@Father註解時,是能夠獲取到父類的@Father註解的。若是一個使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。
@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Native { }
僅僅用來標記native的屬性,只對屬性有效,且只在代碼中使用,通常用於給IDE工具作提示用。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Repeatable { /** * Indicates the <em>containing annotation type</em> for the * repeatable annotation type. * @return the containing annotation type */ Class<? extends Annotation> value(); }
可重複註解的註解,容許在同一申明類型(類,屬性,或方法)的屢次使用同一個註解。
全部註解默認都實現了這個接口,實現是由編譯器完成的,編寫本身的接口的方法:
使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其餘細節。在定義註解時,不能繼承其餘的註解或接口。@interface用來聲明一個註解,其中的每個方法其實是聲明瞭一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)。能夠經過default來聲明參數的默認值。同時value屬性是一個註解的默認屬性,只有value屬性時是能夠不顯示賦值的。
定義註解格式:
public @interface 註解名 {定義體}
使用註解格式:
@註解名(key=value, key=value)
註解參數的可支持數據類型:
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,Annotation等數據類型,以及這一些類型的數組.例如,String value();這裏的參數成員就爲String;數組類型相似於String[] value();
第三,若是隻有一個參數成員,最好把參數名稱設爲"value",後加小括號.或者只有一個參數沒有默認值,其餘都有,也能夠把這個參數名稱設爲"value",這樣使用註解時就不用顯式聲明屬性了。
第四,若是一個參數成員類型爲數組,若是 String[] array();傳值方式爲array={"a","b"},若只有一個值,則能夠直接令array="a",會自動生成一個只包含a的數組。若沒有值,則array={}。都是能夠的。
註解元素的默認值:
註解元素必須有肯定的值,要麼在定義註解的默認值中指定,要麼在使用註解時指定,非基本類型的註解元素的值不可爲null。所以, 使用空字符串或0做爲默認值是一種經常使用的作法。這個約束使得處理器很難表現一個元素的存在或缺失的狀態,由於每一個註解的聲明中,全部元素都存在,而且都具備相應的值,爲了繞開這個約束,咱們只能定義一些特殊的值,例如空字符串或者負數,一次表示某個元素不存在,在定義註解時,這已經成爲一個習慣用法。
Annotation接口中方法:
Class<? extends Annotation> annotationType() 返回此 annotation 的註解類型。
boolean equals(Object obj) 若是指定的對象表示在邏輯上等效於此接口的註解,則返回 true。
String toString() 返回此 annotation 的字符串表示形式。
全部Annotation類中的Class<?> getClass()。
有了元註解,那麼我就可使用它來自定義咱們須要的註解。結合自定義註解和AOP或者過濾器,是一種十分強大的武器。好比可使用註解來實現控制用戶重複數據提交。下面是一個關於重複數據提交驗證註解的實現:
/** * * 一個用戶 相同url 同時提交 相同數據 驗證 * @author lpf * @create 2018-07-09 10:33 **/ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface SameUrlData { }
咱們自定義了一個註解 @SameUrlData , 能夠被用於 方法 上,註解一直保留到運行期,能夠被反射讀取到。該註解的含義是:被 @SameUrlData 註解的方法,不容許用戶重複提交數據。下面就是對註解進行處理了:
/** * 一個用戶 相同url 同時提交 相同數據 驗證 * 主要經過 session中保存到的url 和 請求參數。 * 若是和上次相同,則是重複提交表單 * * @author lpf * @create 2018-07-09 10:35 **/ public class SameUrlDataInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); SameUrlData annotation = method.getAnnotation(SameUrlData.class); if (annotation != null) { if (repeatDataValidator(request)) {//若是重複相同數據 PrintWriter p = response.getWriter(); p.write("不能重複提交數據"); p.flush(); p.close(); return false; } else{ return true; } } return true; } else { return super.preHandle(request, response, handler); } } /** * 驗證同一個url數據是否相同提交 ,相同返回true * * @param httpServletRequest * @return */ public boolean repeatDataValidator(HttpServletRequest httpServletRequest) { String params = JsonMapper.toJsonString(httpServletRequest.getParameterMap()); String url = httpServletRequest.getRequestURI(); Map<String, String> map = new HashMap<String, String>(); map.put(url, params); String nowUrlParams = map.toString();// //上一次請求時間 Object preRequestTime = httpServletRequest.getSession().getAttribute("preRequestTime"); Object preUrlParams = httpServletRequest.getSession().getAttribute("repeatData"); if (preUrlParams == null) {//若是上一個數據爲null,表示尚未訪問頁面 httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams); httpServletRequest.getSession().setAttribute("preRequestTime", new Date().getTime()); return false; } else {//不然,已經訪問過頁面 Date thisDate = new Date(); // 超過30秒鐘 if(thisDate.getTime() - (Long) preRequestTime>30*1000){ httpServletRequest.getSession().setAttribute("preRequestTime", thisDate.getTime()); return false; }else{ if (preUrlParams.toString().equals(nowUrlParams)) {//若是上次url+數據和本次url+數據相同,則表示城府添加數據 return true; } else {//若是上次 url+數據 和本次url加數據不一樣,則不是重複提交 httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams); httpServletRequest.getSession().setAttribute("preRequestTime", thisDate.getTime()); return false; } } } } }
上面咱們定義了一個攔截器,首先使用反射來判斷方法上是否被 @SameUrlData 註解:
HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); SameUrlData annotation = method.getAnnotation(SameUrlData.class);
這是一個簡單的使用 註解 和 過濾器 來進行重複數據提交驗證的例子。