Spring中的注解大概可以分为两大类:
1)spring的bean容器相关的注解,或者说bean工厂相关的注解;
2)springmvc相关的注解。
spring的bean容器相关的注解,先后有:@Required, @Autowired, @PostConstruct, @PreDestory,还有Spring3.0开始支持的JSR-330标准javax.inject.*中的注解(@Inject, @Named, @Qualifier, @Provider, @Scope, @Singleton).
springmvc相关的注解有:@Controller, @RequestMapping, @RequestParam, @ResponseBody等等。
要理解Spring中的注解,先要理解Java中的注解。
1. Java中的注解
Java中1.5中开始引入注解,Java中引入的注解如下
@Override
我们最熟悉的应该是:@Override, 它的定义如下:
/**
* 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,它们就是所谓的“元注解”——就是定义注解的注解,或者说注解注解的注解(晕了...)。
@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保留至运行时,可以被反射读取;
@Target:
/**
* 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 处理并保留在文档中。
@Inherited
/**
* 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的子类。
@native
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Native {
}
仅仅用来标记native的属性,只对属性有效,且只在代码中使用,一般用于给IDE工具做提示用。
@Repeatable
@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();
}
可重复注解的注解,允许在同一申明类型(类,属性,或方法)的多次使用同一个注解。
2.Annotation
所有注解默认都实现了这个接口,实现是由编译器完成的,编写自己的接口的方法:
使用@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()。
3. 使用 元注解 来自定义注解 和 处理自定义注解
有了元注解,那么我就可以使用它来自定义我们需要的注解。结合自定义注解和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);
这是一个简单的使用 注解 和 过滤器 来进行重复数据提交验证的例子。
转载于:https://my.oschina.net/u/3737136/blog/1924720