一、定义Java文件叫做Annotation,用@interface表示。
br/>Java文件叫做Annotation,用@interface表示。
二、元注解
@Retention 从源代码中可以看出,主要用于提示注解要保留多长时间
package java.lang.annotation;
/**

Indicates how long annotations with the annotated type are tobe retained. If no Retention annotation is present onan annotation type declaration, the retention policy defaults to{@code RetentionPolicy.CLASS}.<p>A Retention meta-annotation has effect only if themeta-annotated type is used directly for annotation. It has noeffect if the meta-annotated type is used as a member type inanother annotation type.@author Joshua Bloch@since 1.5@jls 9.6.3.2 @Retention*/
@Documented
br/>*/
@Documented
br/>@Target(ElementType.ANNOTATION_TYPE)
/**Returns the retention policy.@return the retention policy
*/
RetentionPolicy value();
}
有三种取值:
RetentionPolicy.SOURCE 将会被编译器抛弃
RetentionPolicy.CLASS 注解会被编辑器保留在类文件中,但是会被vm抛弃
RetentionPolicy.RUNTIME 注解会被编辑器保留在类文件中,也会被vm保留,所以可以通过反射读取。
package java.lang.annotation;
/**Annotation retention policy. The constants of this enumerated typedescribe the various policies for retaining annotations. They are usedin conjunction with the {@link Retention} meta-annotation type to specifyhow long annotations are to be retained.@author Joshua Bloch@since 1.5
*/
public enum RetentionPolicy {
/**Annotations are to be discarded by the compiler.
*/
SOURCE,
/**Annotations are to be recorded in the class file by the compilerbut need not be retained by the VM at run time. This is the defaultbehavior.
*/
CLASS,
/**Annotations are to be recorded in the class file by the compiler andretained by the VM at run time, so they may be read reflectively.@see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
@Target 用于提示该注解使用的地方@Documented
br/>@Documented
br/>@Target(ElementType.ANNOTATION_TYPE)
/**Returns an array of the kinds of elements an annotation typecan be applied to.@return an array of the kinds of elements an annotation typecan be applied to
*/
ElementType[] value();
}
其中ElementType的取值有下面十种:
ElementType.TYPE 用于类,接口(包括注解)或者枚举类型
ElementType.FIELD 用于属性字段包括枚举常量
ElementType.METHOD 用于方法级别
ElementType.PARAMETER 用于参数声明
ElementType.CONSTRUCTOR 用于构造函数声明
ElementType.LOCAL_VARIABLE 用于局部变量声明
ElementType.ANNOTATION_TYPE 用于注解类型声明
ElementType.PACKAGE 用于包声明
ElementType.TYPE_PARAMETER 用于泛型声明
ElementType.TYPE_USE 用于任意类型声明
public enum ElementType {
/ Class, interface (including annotation type), or enum declaration */
TYPE,
/* Field declaration (includes enum constants) /
FIELD,
/ Method declaration */
METHOD,
/ Formal parameter declaration */
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
}
@Documented 将注解包含在Javadoc中
package java.lang.annotation;
/**Indicates that annotations with a type are to be documented by javadocand similar tools by default. This type should be used to annotate thedeclarations of types whose annotations affect the use of annotatedelements by their clients. If a type declaration is annotated withDocumented, its annotations become part of the public APIof the annotated elements.@author Joshua Bloch@since 1.5*/
@Documented
br/>*/
@Documented
br/>@Target(ElementType.ANNOTATION_TYPE)
}
@Inherited 允许子类继承父类
package java.lang.annotation;
/**Indicates that an annotation type is automatically inherited. Ifan Inherited meta-annotation is present on an annotation typedeclaration, and the user queries the annotation type on a classdeclaration, and the class declaration has no annotation for this type,then the class's superclass will automatically be queried for theannotation type. This process will be repeated until an annotation for thistype is found, or the top of the class hierarchy (Object)is reached. If no superclass has an annotation for this type, thenthe query will indicate that the class in question has no such annotation.<p>Note that this meta-annotation type has no effect if the annotatedtype is used to annotate anything other than a class. Note alsothat this meta-annotation only causes annotations to be inheritedfrom superclasses; annotations on implemented interfaces have noeffect.@author Joshua Bloch@since 1.5@jls 9.6.3.3 @Inherited*/
@Documented
br/>*/
@Documented
br/>@Target(ElementType.ANNOTATION_TYPE)
}
三、自定义注解的使用
创建一个自定义注解
import java.lang.annotation.*;
/**Created Date: 2019/3/1

创建自定义注解
*/
@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)
br/>@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

String value();
}
通过反射获取注解
public class Test {
@TestAnnotation(value = "测试方法")
public static void main(String args[]){
try {
Class c=Test.class;
Method[] methods=c.getDeclaredMethods();
for(Method method:methods){
Annotation[] annotations=method.getDeclaredAnnotations();
for(Annotation annotation:annotations){
TestAnnotation testAnnotation= (TestAnnotation) annotation;
System.out.println(testAnnotation.value());
}
}
} catch (ClassNotFoundException e) {e.printStackTrace();
}
}
}
四、web开发中的运用
在web开发中,权限控制非常重要,所以有些接口会限制必须登录之后才能访问,但是个别接口并没有这种限制。一种方式是把需要过滤的ThinkMarkets代理申请www.kaifx.cn/broker/thinkmarkets.html接口或者方法配置在文件中,每次请求时在拦截器中根据请求的路径与配置文件中的对比过滤。其实还有另外一种方式就是通过注解方式。
定义一个注解NoLogin
@Target(ElementType.METHOD)
br/>e.printStackTrace();
}
}
}
四、web开发中的运用
在web开发中,权限控制非常重要,所以有些接口会限制必须登录之后才能访问,但是个别接口并没有这种限制。一种方式是把需要过滤的ThinkMarkets代理申请www.kaifx.cn/broker/thinkmarkets.html接口或者方法配置在文件中,每次请求时在拦截器中根据请求的路径与配置文件中的对比过滤。其实还有另外一种方式就是通过注解方式。
定义一个注解NoLogin
@Target(ElementType.METHOD)
br/>@Documented
}
标注在方法上
在拦截器中判断方法上是否有NoLogin注解
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
//支持两种方式过滤 1、注解方式 添加@NoLogin注解
HandlerMethod handlerMethod= (HandlerMethod) o;
NoLogin noLogin=handlerMethod.getMethod().getDeclaredAnnotation(NoLogin.class);
if(null!=noLogin){
return true;
}
}
五、java内置的注解
除了上述的四个元注解,java还内置了另外三个注解:
@Override 它没有任何的属性,不能存储任何其他信息。它只能作用于方法之上,编译结束后将被丢弃。在java编译器编译成字节码的时候,一旦发现某个方法被这个注解标识过,就会匹配父类中是否存在同一方法,如果不存在就回编译失败。@Target(ElementType.METHOD)
br/>@Target(ElementType.METHOD)
public @interface Override {
}
@Deprecated 弃用的注解@Documented
br/>@Documented
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
@SuppressWarnings 压制警告,比如某段代码中存在过时的方法,那么在编译过程中,会有warn警告,如果不想出现类似的警告,可在方法上添加这个注解。这个注解有一个value的值,这个value表示需要压制的警告类型。
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention(RetentionPolicy.SOURCE)
br/>@Retention(RetentionPolicy.SOURCE)
/**

The set of warnings that are to be suppressed by the compiler in theannotated element. Duplicate names are permitted. The second andsuccessive occurrences of a name are ignored. The presence ofunrecognized warning names is <i>not</i> an error: Compilers mustignore any warning names they do not recognize. They are, however,free to emit a warning if an annotation contains an unrecognizedwarning name.<p> The string {@code "unchecked"} is used to suppressunchecked warnings. Compiler vendors should document theadditional warning names they support in conjunction with thisannotation type. They are encouraged to cooperate to ensurethat the same names work across multiple compilers.@return the set of warnings to be suppressed
*/
String[] value();
}
六、注解的原理
1、java.lang.annotation.Annotation中有这么一句话:The common interface extended by all annotation types 所有的注解都继承于这个接口。怎么理解呢?其实刚才上面例子中的注解可以理解为:
public @interface TestAnnotation extends Annotation{
}
注解的本质就是一个继承了 Annotation 接口的接口
为了方便理解和掌握注解,还是以刚才的TestAnnotation注解为例。在idea中配置启动参数,方便查看代理产生的类,参数如下:
Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
main方法运行结束后,会在/com/sun/proxy目录下生成一个代理类,反编译之后是这样的:
代理类proxy1重写了TestAnnotation的所有方法,包括value()和从Annotation继承来的equals()、hashCode()等方法。
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.fy.annotation.TestAnnotation;
public final class $Proxy1 extends Proxy implements TestAnnotation {
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m0;
private static Method m3;
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Class annotationType() throws {
try {
return (Class)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String value() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("org.fy.annotation.TestAnnotation").getMethod("annotationType");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("org.fy.annotation.TestAnnotation").getMethod("value");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
在看proxy1构造函数中有一个接口InvocationHandler,这个接口的实例化对象又是谁?
java中有一个专门用于注解类型的代理对象AnnotationInvocationHandler,位于sun.reflect.annotation包中。同样是invoke方法用于处理具体的业务。
public Object invoke(Object var1, Method var2, Object[] var3) {
String var4 = var2.getName();
Class[] var5 = var2.getParameterTypes();
if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) {
return this.equalsImpl(var3[0]);
} else if (var5.length != 0) {
throw new AssertionError("Too many parameters for an annotation method");
} else {
byte var7 = -1;
switch(var4.hashCode()) {
case -1776922004:
if (var4.equals("toString")) {
var7 = 0;
}
break;
case 147696667:
if (var4.equals("hashCode")) {
var7 = 1;
}
break;
case 1444986633:
if (var4.equals("annotationType")) {
var7 = 2;
}
}
switch(var7) {
case 0:
return this.toStringImpl();
case 1:
return this.hashCodeImpl();
case 2:
return this.type;
default:
Object var6 = this.memberValues.get(var4);
if (var6 == null) {
throw new IncompleteAnnotationException(this.type, var4);
} else if (var6 instanceof ExceptionProxy) {
throw ((ExceptionProxy)var6).generateException();
} else {
if (var6.getClass().isArray() && Array.getLength(var6) != 0) {
var6 = this.cloneArray(var6);
}
return var6;
}
}
}
}