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);
这是一个简单的使用 注解 和 过滤器 来进行重复数据提交验证的例子。