Java注解与拦截器
简介
Annotation(注解),也叫元数据。一种代码级别的说明,是JDK5.0引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。 Annotion是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。
注解基础
Annotation能被用来为某个程序元素(类、方法、成员变量等)关联任何的信息。Annotation不影响程序代码的执行,无论增加、删除 Annotation,代码都始终如一的执行,但可以通过Java反射工具对Annotation进行访问和处理。
根据注解使用方法和用途,可以将Annotation分为三类:
JDK内置系统注解
注解的语法比较简单,除了@符号的使用外,他基本与Java固有的语法一致,JavaSE中内置三个标准注解,定义在java.lang中:
- @Override:用于修饰此方法覆盖了父类的方法;
- @Deprecated:用于修饰已经过时的方法,可能在未来版本废弃;
- @SuppressWarnnings:用于通知java编译器禁止特定的编译警告。
元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。
- @Documented
- @Target
- @Retention
- @Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。
Documented
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public@interfaceDocumented{}
@Documented可以用于javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
Target注解
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public@interfaceTarget{ElementType[] value();}
@Target说明了Annotation所修饰的对象范围,它所支持的范围在ElementType枚举中描述。
publicenumElementType{
TYPE,/** Class, interface (including annotation type), or enum declaration */
FIELD,/** Field declaration (includes enum constants) */
METHOD,/** Method declaration */
PARAMETER,/** Parameter declaration */
CONSTRUCTOR,/** Constructor declaration */
LOCAL_VARIABLE,/** Local variable declaration */
ANNOTATION_TYPE,/** Annotation type declaration */
PACKAGE /** Package declaration */}
Retention注解
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public@interfaceRetention{RetentionPolicy value();}
@Retention定义了该Annotation被保留的时间长短。
publicenumRetentionPolicy{
SOURCE,
CLASS,
RUNTIME
}
- SOURCE:被编译器丢弃,仅源文件保留
- CLASS:编译器记录注解在class文件里面,运行时被虚拟机丢弃,默认。
- RUNTIME:编译器记录注解在class文件里面,运行时虚拟机会保留,可通过反射读取。
Inherited注解
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public@interfaceInherited{}
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口。
定义注解格式:
public@interfaceAnnotationName{body...}
注解的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称。 注解参数的可支持数据类型:基本数据类型,String,CLass,enum,Annotation及前面类型的数组。 可以通过default来声明参数的默认值。
仅仅定义注解还不够,重要的是要通过注解处理器来处理自定义的注解,Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。
Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素。
publicinterfaceAnnotatedElement{/** 判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false. */boolean isAnnotationPresent(Class<?extendsAnnotation> annotationClass);/** 返回存在的指定类型的注解,否则返回null */<T extendsAnnotation> T getAnnotation(Class<T> annotationClass);/** 返回所有注解 */Annotation[] getAnnotations();/** 返回直接存在于此元素上的所有注释。 */Annotation[] getDeclaredAnnotations();}
定义注解
定义Before注解,用于在类或者方法时,可在运行时读取。可配置继承Interceptor接口的Class数组。
import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Inherited@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD})public@interfaceBefore{Class<?extendsInterceptor>[] value();}
定义拦截器
拦截器接口,为了方便模拟,方法的参数为Object对象
publicinterfaceInterceptor{void intercept(Object obj);}
定义了三个实现Interceptor接口的类,分别为CommonInterceptor,AuthorityInterceptor和CacheInterceptor。
publicclassCommonInterceptorimplementsInterceptor{@Overridepublicvoid intercept(Object obj){System.out.println("Common Interceptor invoke ... ");}}publicclassAuthorityInterceptorimplementsInterceptor{@Overridepublicvoid intercept(Object obj){System.out.println("Authority Interceptor invoke ... ");}}publicclassCacheInterceptorimplementsInterceptor{@Overridepublicvoid intercept(Object obj){System.out.println("Cache Interceptor invoke ... ");}}
定义Action控制类
对Action类添加了注解和方法上添加了0到多个拦截器。
@Before(CommonInterceptor.class)publicclassAction{@Before(AuthorityInterceptor.class)publicvoid save(){System.out.println("foo");}@Before({CacheInterceptor.class,AuthorityInterceptor.class})publicvoid view(){System.out.println("view");}publicvoid list(){System.out.println("list");}}
定义注解处理器
方法上面的拦截器集合有方法上自定义的拦截器和类上定义的拦截器所组成。 步骤:(1) 取得Class上的Before注解,获得此Class上配置的拦截器;(2) 对Class的每个方法获得Method对象,并获得在此Method上配置的拦截器;(3) 将上面两步获得的拦截器合并,对应方法上所配置的拦截器集合。(4) 配置路由和拦截器的关联关系,路由简单的由类名和方法名组成。
import java.util.HashMap;import java.util.Map;import java.lang.reflect.Method;publicclassInterceptorParse{privatestaticfinalInterceptor[] NULL_INTERCEPTOR_ARRAY =newInterceptor[0];publicMap<String,Interceptor[]> parse(Class klass){Map<String,Interceptor[]> result =newHashMap<String,Interceptor[]>();String className = klass.getName();Before classBefore =(Before)klass.getAnnotation(Before.class);Interceptor[] classInterceptors = getInterceptors(classBefore);//Method[] methods = klass.getMethods();Method[] methods = klass.getDeclaredMethods();for(Method method : methods){String methodName = method.getName();Before methodBefore =(Before)method.getAnnotation(Before.class);Interceptor[] methodInterceptors = getInterceptors(methodBefore);Interceptor[] availableInterceptors = combineInterceptors(classInterceptors, methodInterceptors);
result.put(className+"/"+methodName, availableInterceptors);}return result;}privateInterceptor[] getInterceptors(Before beforeAnnotation){if(beforeAnnotation ==null)return NULL_INTERCEPTOR_ARRAY;Interceptor[] result =null;Class<Interceptor>[] interceptorClasses =(Class<Interceptor>[]) beforeAnnotation.value();if(interceptorClasses !=null&& interceptorClasses.length >0){
result =newInterceptor[interceptorClasses.length];for(int i=0; i<result.length; i++){try{
result[i]=(Interceptor)interceptorClasses[i].newInstance();}catch(Exception e){thrownewRuntimeException(e);}}}return(result !=null)?result:NULL_INTERCEPTOR_ARRAY;}privateInterceptor[] combineInterceptors(Interceptor[] first,Interceptor[] second){if(first.length ==0)return second;if(second.length ==0)return first;Interceptor[] result =newInterceptor[first.length + second.length];int idx =0;for(Interceptor interceptor: first){
result[idx++]= interceptor;}for(Interceptor interceptor: second){
result[idx++]= interceptor;}return result;}publicstaticvoid main(String[] args){InterceptorParse interceptorParse =newInterceptorParse();Map<String,Interceptor[]> map = interceptorParse.parse(Action.class);for(Map.Entry<String,Interceptor[]> entry : map.entrySet()){System.out.println("path: "+ entry.getKey());Interceptor[] interceptors = entry.getValue();for(Interceptor interceptor: interceptors){System.out.println("Interceptor:"+ interceptor.getClass().getName());
interceptor.intercept(null);}System.out.println();}}}
运行结果
path:Action/list
Interceptor:CommonInterceptorCommonInterceptor invoke ...
path:Action/view
Interceptor:CommonInterceptorCommonInterceptor invoke ...Interceptor:CacheInterceptorCacheInterceptor invoke ...Interceptor:AuthorityInterceptorAuthorityInterceptor invoke ...
path:Action/save
Interceptor:CommonInterceptorCommonInterceptor invoke ...Interceptor:AuthorityInterceptorAuthorityInterceptor invoke ...
上一篇: 使用CSS做贝塞尔曲线
下一篇: php无刷新提交表单另一种方法