一、前言
使用注解Annotations可以使代码开发变得更加的灵活多变,从另外一个维度降低了代码的复杂性和耦合度。现在新版本的JDK或主流Spring等框架扩展都提高了注解重要性,主要在java.lang.annotation包中实现,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。
二、知识点&源码
注解主要作用:标记(用于告诉编译器一些信息)、编译时动态处理(动态生成代码)、运行时动态处理(得到注解信息)。分为两类:标准注解、元注解。
1. 标准注解
标准Annotation是指Java自带的几个Annotation,主要有@Override、@Deprecated、@SuppressWarnings
@Override@Target(ElementType.METHOD)@b@@Retention(RetentionPolicy.SOURCE)@b@public @interface Override {@b@}
@Deprecated@Documented@b@@Retention(RetentionPolicy.RUNTIME)@b@public @interface Deprecated {@b@}
@SuppressWarnings@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@b@@Retention(RetentionPolicy.SOURCE)@b@public @interface SuppressWarnings {@b@ String[] value();@b@}
2. 元注解
元注解主要包含4个@Documented、@Inherited、@Retention、@Target,
@Documented - 所修饰的Annotation连同自定义Annotation所修饰的元素一同保存到Javadoc文档中@Documented@b@@Retention(RetentionPolicy.RUNTIME)@b@@Target(ElementType.ANNOTATION_TYPE)@b@public @interface Documented {@b@}
@Inherited - 是一个标记注解,可被继承关系的映射到(子类获取父类的注解Annotation信息)@Documented@b@@Retention(RetentionPolicy.RUNTIME)@b@@Target(ElementType.ANNOTATION_TYPE)@b@public @interface Inherited {@b@}
@Target - 修饰的对象范围,如 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量
>ElementType.CONSTRUCTOR 作用于构造器
>ElementType.FIELD 作用于域/属性
>ElementType.LOCAL_VARIABLE 用于描述局部变量
>ElementType.METHOD 作用于方法
>ElementType.PACKAGE 用于描述包
>ElementType.PARAMETER 用于描述参数
>ElementType.TYPE 用于描述类、接口(包括注解类型) 或enum声明,最常用
>用法如下@Target(ElementType.TYPE) @b@@Target({ ElementType.TYPE, ElementType.METHOD})
>源码@Documented@b@@Retention(RetentionPolicy.RUNTIME)@b@@Target(ElementType.ANNOTATION_TYPE)@b@public @interface Target {@b@ ElementType[] value();@b@}@b@public enum ElementType {@b@ /** Class, interface (including annotation type), or enum declaration */@b@ TYPE,@b@ /** Field declaration (includes enum constants) */@b@ FIELD,@b@ /** Method declaration */@b@ METHOD,@b@ /** Parameter declaration */@b@ PARAMETER,@b@ /** Constructor declaration */@b@ CONSTRUCTOR,@b@ /** Local variable declaration */@b@ LOCAL_VARIABLE,@b@ /** Annotation type declaration */@b@ ANNOTATION_TYPE,@b@ /** Package declaration */@b@ PACKAGE@b@}
@Retention - 描述注解的生命周期(即:被描述的注解在什么范围内有效)RetentionPolicy.RUNTIME //注解会在class字节码文件中存在,在运行时可以通过反射获取到@b@RetentionPolicy.CLASS //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得@b@RetentionPolicy.SOURCE //注解仅存在于源码中,在class字节码文件中不包含
>源码@Documented@b@@Retention(RetentionPolicy.RUNTIME)@b@@Target(ElementType.ANNOTATION_TYPE)@b@public @interface Retention {@b@ RetentionPolicy value();@b@}@b@public enum RetentionPolicy {@b@ /* Annotations are to be discarded by the compiler. */@b@ SOURCE,@b@ /* Annotations are to be recorded in the class file by the compiler@b@ * but need not be retained by the VM at run time. This is the default@b@ * behavior. */@b@ CLASS,@b@ /* Annotations are to be recorded in the class file by the compiler and@b@ * retained by the VM at run time, so they may be read reflectively.@b@ * @see java.lang.reflect.AnnotatedElement */@b@ RUNTIME@b@}
三、自定义注解语法
1、格式定义
public @interface 注解名 {定义体}import java.lang.annotation.Documented;@b@import java.lang.annotation.ElementType;@b@import java.lang.annotation.Inherited;@b@import java.lang.annotation.Retention;@b@import java.lang.annotation.RetentionPolicy;@b@import java.lang.annotation.Target;@b@@b@@Documented@b@@Retention(RetentionPolicy.RUNTIME)@b@@Target(ElementType.METHOD)@b@@Inherited@b@public @interface MyMethod{@b@ String author() default "junni@xwood.net";@b@ String date();@b@ int version() default 1;@b@}
>说明
>>通过@interface 定义,注解名即为自定义注解名
>> 注解配置参数名为注解类的方法名
a) 所有方法没有方法体,方法名即为属性名,没有参数没有修饰符,实际只允许 public & abstract 修饰符,默认为 public ,不允许抛异常
b) 方法返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组,返回类型即为属性类型
c) 若只有一个默认属性,可直接用 value() 函数。一个属性都没有表示该 Annotation 为 Mark Annotation
d) 可以加 default 表示默认值,null不能作为成员默认值
2、调用public class MethodInvoker {@b@ @MyMethod( author ="xwood", date="2016/08/03", version=1)@b@ public String getName() {@b@ return "xwood.net";@b@ }@b@}
3. 测试类import java.lang.reflect.Method;@b@public class Test { @b@ public static void main(String[] args) throws NoSuchMethodException,SecurityException{@b@ Class clazz=MethodInvoker.class;@b@ Method method = clazz.getMethod("getName", new Class[]{});@b@ MyMethod myAnnotation = method.getAnnotation(MyMethod.class); @b@ System.out.println("myAnnotation:"+myAnnotation.author()+";"+myAnnotation.date()+";"+myAnnotation.version());@b@ }@b@}
结果输出myAnnotation:xwood;2016/08/03;1
四、注释工具类
基于Spring的org.springframework.core.annotation.AnnotationUtils/*@b@ * Copyright 2002-2012 the original author or authors.@b@ *@b@ * Licensed under the Apache License, Version 2.0 (the "License");@b@ * you may not use this file except in compliance with the License.@b@ * You may obtain a copy of the License at@b@ *@b@ * http://www.apache.org/licenses/LICENSE-2.0@b@ *@b@ * Unless required by applicable law or agreed to in writing, software@b@ * distributed under the License is distributed on an "AS IS" BASIS,@b@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.@b@ * See the License for the specific language governing permissions and@b@ * limitations under the License.@b@ */@b@@b@package org.springframework.core.annotation;@b@@b@import java.lang.annotation.Annotation;@b@import java.lang.reflect.AnnotatedElement;@b@import java.lang.reflect.Method;@b@import java.util.Arrays;@b@import java.util.Map;@b@import java.util.WeakHashMap;@b@@b@import org.springframework.core.BridgeMethodResolver;@b@import org.springframework.util.Assert;@b@@b@@b@public abstract class AnnotationUtils {@b@@b@@b@static final String VALUE = "value";@b@@b@private static final Map, Boolean> annotatedInterfaceCache = new WeakHashMap, Boolean>();@b@@b@public static T getAnnotation(AnnotatedElement ae, Class annotationType) {@b@T ann = ae.getAnnotation(annotationType);@b@if (ann == null) {@b@for (Annotation metaAnn : ae.getAnnotations()) {@b@ann = metaAnn.annotationType().getAnnotation(annotationType);@b@if (ann != null) {@b@break;@b@}@b@}@b@}@b@return ann;@b@}@b@@b@@b@public static Annotation[] getAnnotations(Method method) {@b@return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();@b@}@b@@b@@b@public static A getAnnotation(Method method, Class annotationType) {@b@Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);@b@A ann = resolvedMethod.getAnnotation(annotationType);@b@if (ann == null) {@b@for (Annotation metaAnn : resolvedMethod.getAnnotations()) {@b@ann = metaAnn.annotationType().getAnnotation(annotationType);@b@if (ann != null) {@b@break;@b@}@b@}@b@}@b@return ann;@b@}@b@@b@@b@public static A findAnnotation(Method method, Class annotationType) {@b@A annotation = getAnnotation(method, annotationType);@b@Class> cl = method.getDeclaringClass();@b@if (annotation == null) {@b@annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());@b@}@b@while (annotation == null) {@b@cl = cl.getSuperclass();@b@if (cl == null || cl == Object.class) {@b@break;@b@}@b@try {@b@Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes());@b@annotation = getAnnotation(equivalentMethod, annotationType);@b@}@b@catch (NoSuchMethodException ex) {@b@// No equivalent method found@b@}@b@if (annotation == null) {@b@annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());@b@}@b@}@b@return annotation;@b@}@b@@b@private static A searchOnInterfaces(Method method, Class annotationType, Class>[] ifcs) {@b@A annotation = null;@b@for (Class> iface : ifcs) {@b@if (isInterfaceWithAnnotatedMethods(iface)) {@b@try {@b@Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());@b@annotation = getAnnotation(equivalentMethod, annotationType);@b@}@b@catch (NoSuchMethodException ex) {@b@// Skip this interface - it doesn't have the method...@b@}@b@if (annotation != null) {@b@break;@b@}@b@}@b@}@b@return annotation;@b@}@b@@b@private static boolean isInterfaceWithAnnotatedMethods(Class> iface) {@b@synchronized (annotatedInterfaceCache) {@b@Boolean flag = annotatedInterfaceCache.get(iface);@b@if (flag != null) {@b@return flag;@b@}@b@boolean found = false;@b@for (Method ifcMethod : iface.getMethods()) {@b@if (ifcMethod.getAnnotations().length > 0) {@b@found = true;@b@break;@b@}@b@}@b@annotatedInterfaceCache.put(iface, found);@b@return found;@b@}@b@}@b@@b@@b@public static A findAnnotation(Class> clazz, Class annotationType) {@b@Assert.notNull(clazz, "Class must not be null");@b@A annotation = clazz.getAnnotation(annotationType);@b@if (annotation != null) {@b@return annotation;@b@}@b@for (Class> ifc : clazz.getInterfaces()) {@b@annotation = findAnnotation(ifc, annotationType);@b@if (annotation != null) {@b@return annotation;@b@}@b@}@b@if (!Annotation.class.isAssignableFrom(clazz)) {@b@for (Annotation ann : clazz.getAnnotations()) {@b@annotation = findAnnotation(ann.annotationType(), annotationType);@b@if (annotation != null) {@b@return annotation;@b@}@b@}@b@}@b@Class> superClass = clazz.getSuperclass();@b@if (superClass == null || superClass == Object.class) {@b@return null;@b@}@b@return findAnnotation(superClass, annotationType);@b@}@b@@b@@b@public static Class> findAnnotationDeclaringClass(Class extends Annotation> annotationType, Class> clazz) {@b@Assert.notNull(annotationType, "Annotation type must not be null");@b@if (clazz == null || clazz.equals(Object.class)) {@b@return null;@b@}@b@return (isAnnotationDeclaredLocally(annotationType, clazz)) ? clazz :@b@findAnnotationDeclaringClass(annotationType, clazz.getSuperclass());@b@}@b@@b@@b@public static boolean isAnnotationDeclaredLocally(Class extends Annotation> annotationType, Class> clazz) {@b@Assert.notNull(annotationType, "Annotation type must not be null");@b@Assert.notNull(clazz, "Class must not be null");@b@boolean declaredLocally = false;@b@for (Annotation annotation : Arrays.asList(clazz.getDeclaredAnnotations())) {@b@if (annotation.annotationType().equals(annotationType)) {@b@declaredLocally = true;@b@break;@b@}@b@}@b@return declaredLocally;@b@}@b@@b@@b@public static boolean isAnnotationInherited(Class extends Annotation> annotationType, Class> clazz) {@b@Assert.notNull(annotationType, "Annotation type must not be null");@b@Assert.notNull(clazz, "Class must not be null");@b@return (clazz.isAnnotationPresent(annotationType) && !isAnnotationDeclaredLocally(annotationType, clazz));@b@}@b@@b@@b@public static Map getAnnotationAttributes(Annotation annotation) {@b@return getAnnotationAttributes(annotation, false, false);@b@}@b@@b@@b@public static Map getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) {@b@return getAnnotationAttributes(annotation, classValuesAsString, false);@b@}@b@@b@@b@public static AnnotationAttributes getAnnotationAttributes(@b@Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {@b@@b@AnnotationAttributes attrs = new AnnotationAttributes();@b@Method[] methods = annotation.annotationType().getDeclaredMethods();@b@for (Method method : methods) {@b@if (method.getParameterTypes().length == 0 && method.getReturnType() != void.class) {@b@try {@b@Object value = method.invoke(annotation);@b@if (classValuesAsString) {@b@if (value instanceof Class) {@b@value = ((Class>) value).getName();@b@}@b@else if (value instanceof Class[]) {@b@Class>[] clazzArray = (Class[]) value;@b@String[] newValue = new String[clazzArray.length];@b@for (int i = 0; i annotationType) {@b@return getDefaultValue(annotationType, VALUE);@b@}@b@@b@@b@public static Object getDefaultValue(Class extends Annotation> annotationType, String attributeName) {@b@try {@b@Method method = annotationType.getDeclaredMethod(attributeName, new Class[0]);@b@return method.getDefaultValue();@b@}@b@catch (Exception ex) {@b@return null;@b@}@b@}@b@@b@}