JAVA的注解

本文详细介绍了如何在Java中自定义注解进行字段赋值、构造工厂解析、校验规则,并通过实例展示了invoke方法的权限管理和MethodAccessor的使用。通过实例代码和元注解分析,深入理解了注解在Java中的应用。
摘要由CSDN通过智能技术生成

1.自定义注解
1.1注解的基础
  • 注解的定义:JAVA文件叫做Annotation,用**@interface**表示

  • 元注解: @interface上面按照需要注解上一些东西,包括**@Retention、@Target、@Document、@Inherited**四种

  • 注解的保留策略:

    • @Retention(RetentionPolicy.SOURCE) //注解仅存在源码中,在class字节码中不包含
    • @Retention(RetentionPolicy.CLASS) //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
    • @Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时通过反射获取到
  • 注解的作用目标

    注解说明
    @Target(ElementType.TYPE)接口、类、枚举、注解
    @Target(ElementType.FIELD)字段、枚举的常量
    @Target(ElementType.METHOD)方法
    @Target(ElementType.PARAMETER)方法参数
    @Target(ElementType.CONSTRUCTOR)构造函数
    @Target(ElementType.LOCAL_VARIABLE)局部变量
    @Target(ElementType.ANNOTATION_TYPE)注解
    @Target(ElementType.PACKAGE)
  • 注解包含在javadoc中**@Documented**

  • 注解可以被继承**@Inherited**

  • 注解解析器: 用来解析自定义注解

1.2通过注解进行赋值(结合工厂模式)
1.2.1自定义注解
@Documented
@Inherited
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Init {

    public String value() default "";
}
1.2.2在数据模型使用注解
public class User {
    private String name;
    private String age;

    public String getName() {
        return name;
    }
    @Init(value = "liang")
    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }
    @Init(value = "23")
    public void setAge(String age) {
        this.age = age;
    }
}
1.2.3用"构造工厂"充当"注解解析器"
public class UserFactory {
    public static User create(){
        User user = new User();
        Method[] declaredMethods = User.class.getDeclaredMethods();
        try {
            for (Method method:declaredMethods){
                if (method.isAnnotationPresent(Init.class)){
                    Init annotation = method.getAnnotation(Init.class);

                        method.invoke(user,annotation.value());
                }
            }
        }catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            return null;
        }
        return user;
    }
}
  • 结合源码

     @CallerSensitive
        public Object invoke(Object obj, Object... args)
            throws IllegalAccessException, IllegalArgumentException,
               InvocationTargetException
        {
            if (!override) {
                if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                    Class<?> caller = Reflection.getCallerClass();
                    checkAccess(caller, clazz, obj, modifiers);
                }
            }
            MethodAccessor ma = methodAccessor;             // read volatile
            if (ma == null) {
                ma = acquireMethodAccessor();
            }
            return ma.invoke(obj, args);
        }
    
1.2.4运行的代码
public class test {
    public static void main(String[] args) {
        User user = UserFactory.create();
        System.out.println(user.getAge());
        System.out.println(user.getAge());
    }
}
1.3通过注解进行校验
1.3.1自定义注解
@Documented
@Inherited
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {
    public int min() default 1;
    public int max() default 10;
    public boolean isNotNull() default true;
}
1.3.2在数据模型使用注解
public class User {
    @Validate(min = 2,max = 5)
    private String name;
    @Validate(isNotNull = false)
    private String age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}
1.3.3注解解析器
public class UserCheck {
    public static boolean check(User user){
        if (user == null){
            System.out.println("校验对象为空");
            return false;
        }
        Field[] declaredFields = User.class.getDeclaredFields();
        for (Field field:declaredFields){
            //注解Validate是否在field上面
            if (field.isAnnotationPresent(Validate.class)){
                Validate annotation = field.getAnnotation(Validate.class);
                if (field.getName().equals("age")){
                    if (user.getAge() == null){
                        if (annotation.isNotNull()){
                            System.out.println("年龄可空检验不通过;不可为空");
                            return false;
                        }else{
                            System.out.println("年龄可检验通过,可以为空");
                            continue;
                        }
                    }else{
                        System.out.println("年龄可校验通过");
                    }
                    if (user.getAge().length() < annotation.min()){
                        System.out.println("年龄最小长度校验不通过");
                        return false;
                    }else {
                        System.out.println("年龄最小长度校验通过");
                    }
                    if (user.getAge().length() > annotation.max()){
                        System.out.println("年龄最长度校验不通过");
                        return false;
                    }else{
                        System.out.println("年龄最长度校验通过");
                    }
                }
                if (field.getName().equals("name")){
                    if (user.getName() == null){
                        if (annotation.isNotNull()){
                            System.out.println("名字校验不通过:不可为空");
                            return false;
                        }else {
                            System.out.println("名字可检验通过:可以为空");
                            continue;
                        }


                    }else {
                        System.out.println("名字可空校验通过");
                    }
                    if (user.getName().length() < annotation.min()){
                        System.out.println("名字最小长度校验不通过");
                        return false;
                    }else{
                        System.out.println("名字最小长度校验通过");
                    }
                    if (user.getName().length() > annotation.max()){
                        System.out.println("名字最长度校验不通过");
                        return false;
                    }else{
                        System.out.println("名字最长度校验通过");
                    }
                }
            }
        }
        return true;
    }
}
1.3.4运行的代码
public class Test {
    public static void main(String[] args) {
        User user = new User();
        user.setName("liang");
        user.setAge("234");
        System.out.println(UserCheck.check(user));
    }
}
1.4invoke方法
1.4.1invoke方法用来运行时动态地调用某个实例的方法
###########################源码###################
@CallerSensitive
public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
       InvocationTargetException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}
1.4.2权限检查
  • invoke方法会首先检查AccessibleObjectoverride属性值,AccessibleObject类是FieldMethodConstructor对象的基类,它提供了将反射的对象标记为使用时取消默认java语言访问控制检查的能力

  • override的默认是false,表示需要权限调用规则,调用方法时需要检查权限,我们也可以用setAccessible方法设置为true,若override的值为true,表示忽略权限规则,调用方法时无需检查权限(也就是说可以调用任意的private方法,违反了封装的意义)

  • 如果override属性默认值false,则进行进一步的权限检查

    • 首先用**Reflection.quickCheckMemberAccess(clazz,modifiers)方法检查方法是否为public,如果是的话跳出本步,如果不是public方法,那么用Reflection.getCallerClass()**方法获取调用这个方法的Class对象,这是一个native方法:

      @CallerSensitive
      public static native Class<?> getCallerClass();
      
    • 在OpenJDK的源码中找到此方法的JNI入口(Reflection.c)

      JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__
      (JNIEnv *env, jclass unused)
      {
          return JVM_GetCallerClass(env, JVM_CALLER_DEPTH);
      }
      
    • 其中JVM_GetCallerClass的源码如下(JVM.cpp)

      JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env, int depth))
        JVMWrapper("JVM_GetCallerClass");
        // Pre-JDK 8 and early builds of JDK 8 don't have a CallerSensitive annotation; or
        // sun.reflect.Reflection.getCallerClass with a depth parameter is provided
        // temporarily for existing code to use until a replacement API is defined.
        if (SystemDictionary::reflect_CallerSensitive_klass() == NULL || depth != JVM_CALLER_DEPTH) {
          Klass* k = thread->security_get_caller_class(depth);
          return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror());
        }
        // Getting the class of the caller frame.
        //
        // The call stack at this point looks something like this:
        //
        // [0] [ @CallerSensitive public sun.reflect.Reflection.getCallerClass ]
        // [1] [ @CallerSensitive API.method                                   ]
        // [.] [ (skipped intermediate frames)                                 ]
        // [n] [ caller                                                        ]
        vframeStream vfst(thread);
        // Cf. LibraryCallKit::inline_native_Reflection_getCallerClass
        for (int n = 0; !vfst.at_end(); vfst.security_next(), n++) {
          Method* m = vfst.method();
          assert(m != NULL, "sanity");
          switch (n) {
          case 0:
            // This must only be called from Reflection.getCallerClass
            if (m->intrinsic_id() != vmIntrinsics::_getCallerClass) {
              THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVM_GetCallerClass must only be called from Reflection.getCallerClass");
            }
            // fall-through
          case 1:
            // Frame 0 and 1 must be caller sensitive.
            if (!m->caller_sensitive()) {
              THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), err_msg("CallerSensitive annotation expected at frame %d", n));
            }
            break;
          default:
            if (!m->is_ignored_by_security_stack_walk()) {
              // We have reached the desired frame; return the holder class.
              return (jclass) JNIHandles::make_local(env, m->method_holder()->java_mirror());
            }
            break;
          }
        }
        return NULL;
      JVM_END
      
    • 获取了这个Class对象caller后用checkAccess方法做一次快速的权限校验,其实现为:

      volatile Object securityCheckCache;
          void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers)
              throws IllegalAccessException
          {
              if (caller == clazz) {  // 快速校验
                  return;             // 权限通过校验
              }
              Object cache = securityCheckCache;  // read volatile
              Class<?> targetClass = clazz;
              if (obj != null
                  && Modifier.isProtected(modifiers)
                  && ((targetClass = obj.getClass()) != clazz)) {
                  // Must match a 2-list of { caller, targetClass }.
                  if (cache instanceof Class[]) {
                      Class<?>[] cache2 = (Class<?>[]) cache;
                      if (cache2[1] == targetClass &&
                          cache2[0] == caller) {
                          return;     // ACCESS IS OK
                      }
                      // (Test cache[1] first since range check for [1]
                      // subsumes range check for [0].)
                  }
              } else if (cache == caller) {
                  // Non-protected case (or obj.class == this.clazz).
                  return;             // ACCESS IS OK
              }
              // If no return, fall through to the slow path.
              slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
          }
      
      • 首先先执行一次快速校验,一旦调用方法的Class正确则权限检查通过

      • 若未通过,则创建一个缓存,中间再进行一堆检查(比如检验是否为protected属性)

      • 如果上面的所有权限检查都未通过,那么将执行更加详细的检查,其实现为:

        // Keep all this slow stuff out of line:
        void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers,
                                   Class<?> targetClass)
            throws IllegalAccessException
        {
            Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
            // Success: Update the cache.
            Object cache = ((targetClass == clazz)
                            ? caller
                            : new Class<?>[] { caller, targetClass });
            // Note:  The two cache elements are not volatile,
            // but they are effectively final.  The Java memory model
            // guarantees that the initializing stores for the cache
            // elements will occur before the volatile write.
            securityCheckCache = cache;         // write volatile
        }
        
      • 大体意思就是,用Reflection.ensureMemberAccess方法继续检查权限,若检查通过就更新缓存,这样下一次同一个类调用同一个方法时就不用执行权限检查了,这就是一种简单的缓存机制,由于JMM的到这里,前期的权限检查工作就结束,如果没有通过检查则会抛出异常,如果通过检查则到下一步。

1.4.3调用MethodAccessor的invoke方法
  • Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理
  • 首先要了解Method对象的基本构成,每个java方法有且只有一个Method对象作为root,它相当于根对象,对用户不可见。当我们创建Method对象时,代码中获得的Method对象都相当于它的副本(或引用)。root对象持有一个MethodAccessor对象,所有所有获取到Method对象都共享这个MethodAccessor对象,因此必须保证它再内存中的可见性,root对象其声明及注释为:
private volatile MethodAccessor methodAccessor;
// For sharing of MethodAccessors. This branching structure is
// currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.)
//
// If this branching structure would ever contain cycles, deadlocks can
// occur in annotation code.
private Method  root;
  • 那么MethodAccessor到底是什么

    /** This interface provides the declaration for
        java.lang.reflect.Method.invoke(). Each Method object is
        configured with a (possibly dynamically-generated) class which
        implements this interface.
    */
    	public interface MethodAccessor {
        /** Matches specification in {@link java.lang.reflect.Method} */
        public Object invoke(Object obj, Object[] args)
            throws IllegalArgumentException, InvocationTargetException;
    }
    
  • 可以看到MethodAccessor是一个接口,定义了invoke方法,分析其Usage可得它的具体实现类有

    sun.reflect.DelegatingMethodAccessorImpl
    sun.reflect.MethodAccessorImpl
    sun.reflect.NativeMethodAccessorImpl
    

重大遗留问题】 我理解不了:https://www.sczyh30.com/posts/Java/java-reflection-2/

1.5总结
public class Reflecttion {
    public static void main(String[] args) {
        /**
         * 获取Class对象 三种方式
         * Class.forName("")
         * 类名.class
         * 对象名.getClass()
         *
         */
        Class clazz = Student.class;
       /* Class clazz1 = null;
        try {
            clazz1 = Class.forName("com.lc.testReflection.Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Class clazz2 = (new Student()).getClass();*/
        /**
         * Class用来描述目标类的结构
         * getInterfaces()  //返回运行时实现的全部接口
         * getSuperclass()  //返回运行时类的父类
         * getConstructors()  //返回运行时类的public构造方法
         * getDeclaredConstructors()  //返回运行时类的全部构造方法
         * getMethods()  //返回运行时类的public方法,包括其继承的公用方法
         * getDeclaredMethods()  //返回运行时类的全部方法,但是不包括继承的方法
         * getFields()  //返回运行时类的public成员变量,包括继承的public成员变量
         * getDeclaredFields()  //返回运行时类的全部成员变量,但不包括继承的成员变量
         * getMethod(String name,Class<?> ... parameterTypes) //返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应的Class的对象
         */
        //返回运行时类实现的全部接口
        Class[] interfaces = clazz.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);
        }
        //返回运行时类的父类
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
        //返回运行时类的public构造方法
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        //返回运行时类的全部构造方法
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        //返回运行时类的public方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        //返回运行时类的全部方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        //返回运行时类的public成员变量
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        //返回运行类的全部成员变量
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        //返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应的Class的对象
        Method method = clazz.getMethod("方法名称",参数类型.class,...)
        
        
        /**
         * getReturnType();  //返回方法的返回值类型
         * getParameterTypes();  //返回方法的参数列表
         * getModifiers(); //返回方法的访问权限修饰符  0:无修饰 1:public 2:private 4:protected
         * getName();  //返回方法名
         * getExceptionTypes();  //返回方法的异常信息
         *
         *
         * 获取方法后可以通过invoke();//来完成方法的调取
         */
        //获取指定方法的(how())
        Method how = null;
        try {
            how = clazz.getDeclaredMethod("how", null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        //返回方法的返回值类型
        Class<?> returnType = how.getReturnType();
        System.out.println(returnType);
        //返回方法的参数列表
        Class<?>[] parameterTypes = how.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println(parameterType);
        }
        //返回方法的访问权限修饰符
        int modifiers = how.getModifiers();
        System.out.println(modifiers);
        //返回方法名
        String name = how.getName();
        System.out.println(name);
        //返回方法的异常信息
        Class<?>[] exceptionTypes = how.getExceptionTypes();
        for (Class<?> exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

        /**
         * Field用来描述运行时类的成员变量
         * getModifiers();  //返回成员变量访问权限修饰符
         * getType();  //返回成员变量的数据类型
         * getName();  //返回成员变量的名称
         *
         * 获取成员变量后
         * ##setAccessible(boolean);//值为ture,表示能修改,值为false,表示不能修改,会抛出异常,默认为false(任意修饰符)
         * set(Object object,Types types);//eg:field.set(student,1)
         *
         */
        //指定成员变量
        Field name1 = null;
        try {
            name1 = clazz.getField("name");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        //返回成员变量的访问权限修饰符
        int modifiers1 = name1.getModifiers();
        System.out.println(modifiers1);
        //返回成员变量的数据类型
        Class<?> type = name1.getType();
        System.out.println(type);
        //返回成员变量的名称
        String name2 = name1.getName();
        System.out.println(name2);

        /**
         * constructor用来描述运行时类的构造方法
         * getModifiers();  //返回构造方法的访问权限修饰符
         * getName();   //返回构造方法名称
         * getParameterTypes();   //返回构造方法参数列表
         *
         * 通过指定参数列表获取对应构造函数
         * eg:clazz.getConstructor(int.class,String.class)
         */
        Constructor constructor = null;
        try {
            constructor = clazz.getConstructor(null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //返回构造方法的访问权限修饰符
        int modifiers2 = constructor.getModifiers();
        System.out.println(modifiers2);
        //返回构造方法名称
        String name3 = constructor.getName();
        System.out.println(name3);
        //返回构造方法参数列表
        Class[] parameterTypes1 = constructor.getParameterTypes();
        for (Class aClass : parameterTypes1) {
            System.out.println(aClass);
        }
    }

}
class Student{
    private int id;
    public String name;

    public Student() {
    }

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private void show(){
        System.out.println("id"+id+","+"name"+name);
    }
    protected String how(){
        int a = 10;
        int b = 12;
        return Integer.toString(a+b);
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }



    //动态代理
    class MyInvocationHandler implements InvocationHandler{
        private Object object = null;
        public Object bind(Object object){
            this.object = object;
            return Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(),object.getClass().getInterfaces(),this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(object,args);
            return result;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值