java 注解 annotation 的使用以及反射如何获取注解
这里有新鲜出炉的 Java 并发编程示例, 程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
这篇文章主要介绍了 java 注解 annotation 的使用以及反射如何获取注解的相关资料, 需要的朋友可以参考下
一注解基本知识
1 元注解
元注解是指注解的注解包括 @Retention @Target @Document @Inherited 四种
1. Annotation 型定义为 @interface, 所有的 Annotation 会自动继承 java.lang.Annotation 这一接口, 并且不能再去继承别的类或是接口.
2. 参数成员只能用 public 或默认 (default) 这两个访问权修饰
3. 参数成员只能用基本类型 byte,short,char,int,long,float,double,boolean 八种基本数据类型和 StringEnumClassannotations 等数据类型, 以及这一些类型的数组.
4. 要获取类方法和字段的注解信息, 必须通过 Java 的反射技术来获取 Annotation 对象, 因为你除此之外没有别的获取注解对象的方法
5. 注解也可以没有定义成员, 不过这样注解就没啥用了
自定义注解类时, 可以指定目标 (类方法字段, 构造函数等) , 注解的生命周期(运行时, class 文件或者源码中有效), 是否将注解包含在 javadoc 中及是否允许子类继承父类中的注解, 具体如下:
1. @Target 表示该注解目标, 可能的 ElemenetType 参数包括:
ElemenetType.CONSTRUCTOR 构造器声明
ElemenetType.FIELD 域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE 局部变量声明
ElemenetType.METHOD 方法声明
ElemenetType.PACKAGE 包声明
ElemenetType.PARAMETER 参数声明
ElemenetType.TYPE 类, 接口 (包括注解类型) 或 enum 声明
2. @Retention 表示该注解的生命周期, 可选的 RetentionPolicy 参数包括
RetentionPolicy.SOURCE 注解将被编译器丢弃
RetentionPolicy.CLASS 注解在 class 文件中可用, 但会被 VM 丢弃
RetentionPolicy.RUNTIME VM 将在运行期也保留注释, 因此可以通过反射机制读取注解的信息
3. @Documented 指示将此注解包含在 javadoc 中
4. @Inherited 指示允许子类继承父类中的注解
二在 java 中如何使用
2.1 定义注解
- package com.test.annotation;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- public class MyAnnotation {
- /**
- * 注解类
- * @author T4980D
- *
- */
- @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE) public@interface MyClassAnnotation {
- String uri();
- String desc();
- }
- /**
- * 构造方法注解
- * @author T4980D
- *
- */
- @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.CONSTRUCTOR) public@interface MyConstructorAnnotation {
- String uri();
- String desc();
- }
- /**
- * 我的方法注解
- * @author Owner
- *
- */
- @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD) public@interface MyMethodAnnotation {
- String uri();
- String desc();
- }
- /**
- * 字段注解定义
- * @author Owner
- *
- */
- @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD) public@interface MyFieldAnnotation {
- String uri();
- String desc();
- }
- /**
- *
- * 可以同时应用到类上和方法上
- * @author T4980D
- *
- */
- @Target({
- ElementType.TYPE,
- ElementType.METHOD
- })@Retention(RetentionPolicy.RUNTIME) public@interface Yts {
- // 定义枚举
- public enum YtsType {
- util,
- entity,
- service,
- model
- }
- // 设置默认值
- public YtsType classType()
- default YtsType.util;
- // 数组
- int[] arr()
- default {
- 3,
- 7,
- 5
- };
- String color()
- default "blue";
- }
- }
2.2 基本测试注解
- package com.test.annotation;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import com.test.annotation.MyAnnotation.MyClassAnnotation;
- import com.test.annotation.MyAnnotation.MyConstructorAnnotation;
- import com.test.annotation.MyAnnotation.MyFieldAnnotation;
- import com.test.annotation.MyAnnotation.MyMethodAnnotation;
- import com.test.annotation.MyAnnotation.Yts;
- import com.test.annotation.MyAnnotation.Yts.YtsType;
- @MyClassAnnotation(desc = "The class", uri = "com.test.annotation.Test")
- @Yts(classType =YtsType.util)
- public class TestAnnotation {
- @MyFieldAnnotation(desc = "The class field", uri = "com.test.annotation.Test#id")
- private String id;
- @MyConstructorAnnotation(desc = "The class constructor", uri = "com.test.annotation.Test#MySample")
- public TestAnnotation() {
- }
- public String getId() {
- return id;
- }
- @MyMethodAnnotation(desc = "The class method", uri = "com.test.annotation.Test#setId")
- public void setId(String id) {
- System.out.println("method info:"+id);
- this.id = id;
- }
- @MyMethodAnnotation(desc = "The class method sayHello", uri = "com.test.annotation.Test#sayHello")
- @Yts
- public void sayHello(String name){
- if(name == null || name.equals("")){
- System.out.println("hello world!");
- }else{
- System.out.println(name + "\t:say hello world!");
- }
- }
- public static void main(String[] args) throws Exception {
- Class<TestAnnotation> clazz = TestAnnotation.class;
- // 得到类注解
- MyClassAnnotation myClassAnnotation = clazz.getAnnotation(MyClassAnnotation.class);
- System.out.println(myClassAnnotation.desc() + " "+ myClassAnnotation.uri());
- // 得到构造方法注解
- Constructor<TestAnnotation> cons = clazz.getConstructor(new Class[]{});
- MyConstructorAnnotation myConstructorAnnotation = cons.getAnnotation(MyConstructorAnnotation.class);
- System.out.println(myConstructorAnnotation.desc() + " "+ myConstructorAnnotation.uri());
- // 获取方法注解
- Method method = clazz.getMethod("setId", new Class[]{int.class});
- MyMethodAnnotation myMethodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
- System.out.println(myMethodAnnotation.desc() + " "+ myMethodAnnotation.uri());
- // 获取字段注解
- Field field = clazz.getDeclaredField("id");
- MyFieldAnnotation myFieldAnnotation = field.getAnnotation(MyFieldAnnotation.class);
- System.out.println(myFieldAnnotation.desc() + " "+ myFieldAnnotation.uri());
- }
- }
2.3 通过反射解析
- package com.test.annotation;
- import java.lang.reflect.Method;
- import java.util.Arrays;
- import com.test.annotation.MyAnnotation.MyClassAnnotation;
- import com.test.annotation.MyAnnotation.MyMethodAnnotation;
- import com.test.annotation.MyAnnotation.Yts;
- import com.test.annotation.MyAnnotation.Yts.YtsType;
- public class ParseAnnotation {
- /**
- * 解析方法注解
- * @param <T>
- * @param clazz
- */
- public static < T > void parseMethod(Class < T > clazz) {
- try {
- T obj = clazz.newInstance();
- for (Method method: clazz.getDeclaredMethods()) {
- MyMethodAnnotation methodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
- if (methodAnnotation != null) {
- // 通过反射调用带有此注解的方法
- method.invoke(obj, methodAnnotation.uri());
- }
- Yts yts = (Yts) method.getAnnotation(Yts.class);
- if (yts != null) {
- if (YtsType.util.equals(yts.classType())) {
- System.out.println("this is a util method");
- } else {
- System.out.println("this is a other method");
- }
- System.out.println(Arrays.toString(yts.arr())); // 打印数组
- System.out.println(yts.color()); // 输出颜色
- }
- System.out.println("\t\t-----------------------");
- }
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 解析类注解
- * @param <T>
- * @param clazz
- */
- public static < T > void parseType(Class < T > clazz) {
- try {
- Yts yts = (Yts) clazz.getAnnotation(Yts.class);
- if (yts != null) {
- if (YtsType.util.equals(yts.classType())) {
- System.out.println("this is a util class");
- } else {
- System.out.println("this is a other class");
- }
- }
- MyClassAnnotation classAnnotation = (MyClassAnnotation) clazz.getAnnotation(MyClassAnnotation.class);
- if (classAnnotation != null) {
- System.err.println("class info:" + classAnnotation.uri());
- }
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- parseMethod(TestAnnotation.class);
- parseType(TestAnnotation.class);
- }
- }
三注解应用案例
3.1 关于细粒度权限拦截的问题, 在 Struts2 中可以根据登录用户所具有的的权限进行任一一个 action 方法的拦截, 可以定义一个自定义方法注解, 例如
- @Retention(RetentionPolicy.RUNTIME) // 代表 Permission 注解保留在的阶段
- @Target(ElementType.METHOD) // 标注在方法上面
- public@interface Permission {
- /** 模块 */
- String module();
- /** 权限值 */
- String privilege();
- }
32 比如有一个部门 action,Department.action, 有一个方法 public String departmentlistUI(){}可以这样定义方法
- @Permission(module="department",privilege="view")
- public String departmentlistUI(){
- }
3.3 然后自定定义一个权限拦截器 PrivilegeInterceptor.java 并在 struts.xml 中注册, 在实现 interceptor 接口后, 实现方法 public String intercept(ActionInvocation invocation) throws Exception {}, 在这里调用任一个 action 方法都会经过该拦截方法, 通过 invocation 可以获取当前调用的 action 的名字, 以及调用的 action 的哪个方法, 通过这段代码可以获取 action 名字和方法名
- String actionName = invocation.getProxy().getActionName();
- String methodName = invocation.getProxy().getMethod();
- System.out.println("拦截到: action 的名字:" + actionName + "方法名:" + methodName);
4 然后通过反射技术, 获取该方法上的自定义权限注解, 获取当前登录的用户(从 session 中), 遍历当前用户的所拥有的权限组, 并且遍历任一个权限组下的所有的权限, 看是否包括该方法上注解所需的权限这样就可以完成细粒度的 action 方法权限拦截了
- private boolean validate(ActionInvocation invocation) throws SecurityException,
- NoSuchMethodException {
- String methodName = invocation.getProxy().getMethod();
- Method currentMethod = invocation.getAction().getClass().getMethod(methodName);
- if (currentMethod != null && currentMethod.isAnnotationPresent(Permission.class)) {
- // 得到方法上的注解
- Permission permission = currentMethod.getAnnotation(Permission.class);
- // 该方法上的所需要的权限
- SystemPrivilege methodPrivilege = new SystemPrivilege(new SystemPrivilegePK(permission.module(), permission.privilege()));
- // 得到当前登录的用户
- Employee e = (Employee) ActionContext.getContext().getSession().get("loginUser");
- // 遍历当前用户下的所有的权限组
- for (PrivilegeGroup group: e.getGroups()) {
- // 如果该权限组下包含, 要访问该方法所需要的权限, 就放行
- if (group.getPrivileges().contains(methodPrivilege)) {
- return true;
- }
- }
- // 说明遍历的该用户所有的权限组, 没有发现该权限, 说明没有该权限
- return false;
- }
- // 没有标注注解, 表示谁都可以调用该方法
- return true;
- }
来源: http://www.phperz.com/article/18/0211/358812.html