注解反射以及动态代理

注解与反射以及动态代理

注解

注解的定义

Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。

基本规则:Annotation不能影响程序代码的执行,无论增加、删除 Annotation,代码都始终如一的执行。

什么是元数据

  1. 元数据以标签的形式存在于Java代码中。
  2. 元数据描述的信息是类型安全的,即元数据内部的字段都是有明确类型的。
  3. 元数据需要编译器之外的工具额外的处理用来生成其它的程序部件。
  4. 元数据可以只存在于Java源代码级别,也可以存在于编译之后的Class文件内部。

注解的原理

当Java源代码被编译时,编译器的一个插件annotation处理器则会处理这些annotation。处理器可以产生报告信息,或者创建附加的Java源文件或资源。如果annotation本身被加上了RententionPolicy的运行时类,则Java编译器则会将annotation的元数据存储到class文件中。然后,Java虚拟机或其他的程序可以查找这些元数据并做相应的处理。当然除了annotation处理器可以处理annotation外,我们也可以使用反射自己来处理annotation

注解的分类

系统内置标准注解

  1. @Override(标记注解类型)
  2. @Deprecated(标志已过时),
  3. @SuppressWarnings(抑制编译器警告)

元注解

在定义注解时,注解类也能够使用其他的注解声明。对注解类型进行注解的注解类,我们称之为 meta�

annotation(元注解)。一般的,我们在定义自定义注解时,需要指定的元注解有两个 :

另外还有@Documented@Inherited 元注解,前者用于被javadoc工具提取成文档,后者表示允许子类继承父类中定义的注解。

@Target

注解标记另一个注解,以限制可以应用注解的 Java 元素类型。目标注解指定以下元素类型之一作为其值:

  • ElementType.ANNOTATION_TYPE 可以应用于注解类型。

  • ElementType.CONSTRUCTOR 可以应用于构造函数。

  • ElementType.FIELD 可以应用于字段或属性。

  • ElementType.LOCAL_VARIABLE 可以应用于局部变量。

  • ElementType.METHOD 可以应用于方法级注解。

  • ElementType.PACKAGE 可以应用于包声明。

  • ElementType.PARAMETER 可以应用于方法的参数。

  • ElementType.TYPE 可以应用于类的任何元素。

@Retention

注解指定标记注解的存储方式:

  • RetentionPolicy.SOURCE - 标记的注解仅保留在源级别中,并被编译器忽略。

  • RetentionPolicy.CLASS - 标记的注解在编译时由编译器保留,但 Java 虚拟机(JVM)会忽略。

  • RetentionPolicy.RUNTIME - 标记的注解由 JVM 保留,因此运行时环境可以使用它。

@Retention 三个值中 SOURCE < CLASS < RUNTIME,即CLASS包含了SOURCE,RUNTIME包含SOURCE、CLASS。下文会介绍他们不同的应用场景。

Android support annotations

  1. Nullness注解
  2. Resource Type 注解(@StringRes,@ColorInt等)
  3. Threading 注解(@UiThread UI线程,
    ,@MainThread 主线程,@WorkerThread 子线程,
    @BinderThread 绑定线程
  4. Overriding Methods 注解: @CallSuper

注解的应用场景

按照@Retention 元注解定义的注解存储方式,注解可以被在三种场景下使用:

SOURCE

RetentionPolicy.SOURCE ,作用于源码级别的注解,可提供给IDE语法检查、APT等场景使用。

IDE语法检查

在Android开发中, support-annotations 与 androidx.annotation) 中均有提供 @IntDef 注解,此注解的定义如下:

@Retention(SOURCE) //源码级别注解
@Target({ANNOTATION_TYPE})
public @interface IntDef {
    int[] value() default {};
    boolean flag() default false;
    boolean open() default false;
}

Java中Enum(枚举)的实质是特殊单例的静态成员变量,在运行期所有枚举类作为单例,全部加载到内存中。比常量多5到10倍的内存占用。

APT技术

APT全称为:"Anotation Processor Tools",意为注解处理器。顾名思义,其用于处理注解。编写好的Java源文件,需要经过 javac 的编译,翻译为虚拟机能够加载解析的字节码Class文件。注解处理器是 javac 自带的一个工具,用来在编译时期扫描处理注解信息。你可以为某些注解注册自己的注解处理器。 注册的注解处理器由 javac调起,并将注解信息传递给注解处理器进行处理。

注解处理器是对注解应用最为广泛的场景。在Glide、EventBus3、Butterknifer、Tinker、ARouter等等常用框架中都有注解处理器的身影。但是你可能会发现,这些框架中对注解的定义并不是 SOURCE 级别,更多的是 CLASS 级别,别忘了:CLASS包含了SOURCE,RUNTIME包含SOURCE、CLASS。

注解处理器的创建步骤

  1. Android Studio创建一个java library

  2. 自定义一个注解(Annotation),用于存储元数据

    @Retention(RetentionPolicy.CLASS)
    @Target({ElementType.FIELD})
    public @interface Print {
    }
    
  3. 创建一个自定义Annotation Processor继承于AbstractProcessor

    @AutoService(Print.class)
    @SupportedAnnotationTypes("com.lbz.apt_annotation.Print")
    public class MyProcessor extends AbstractProcessor {
        @Override
        public boolean process(Set annotations, RoundEnvironment roundEnv) {
            return false;
        }
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            System.out.println("Hello APT");
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Hello APT");
            super.init(processingEnv);
        }
    
    
        @Override
        public Set getSupportedAnnotationTypes() {
            HashSet strings = new HashSet<>();
            strings.add(Print.class.getCanonicalName());
            return super.getSupportedAnnotationTypes();
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return processingEnv.getSourceVersion();
        }
    

    @AutoService(MyProcessor.class) :向javac注册我们这个自定义的注解处理器,这样,在javac编译时,才会调用到我们这个自定义的注解处理器方法。
    AutoService这里主要是用来生成
    META-INF/services/javax.annotation.processing.Processor文件的。如果不加上这个注解,那么,你需要自己进行手动配置进行注册,具体手动注册方法如下:
    创建一个META-INF/services/javax.annotation.processing.Processor文件, 其内容是一系列的自定义注解处理器完整有效类名集合:

    com.lbz.apt_processor.MyProcessor
    
    1. 编写process方法

CLASS

字节码增强,在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。

RUNTIME

在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。

反射

什么是反射

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的,并且能够获得此类的引用。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。

反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。这时候,我们使用 JDK 提供的反射 API 进行反射调用。反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。是Java被视为动态语言的关键。

Java反射机制主要提供了以下功能:

  • 在运行时构造任意一个类的对象

  • 在运行时获取或者修改任意一个类所具有的成员变量和方法

  • 在运行时调用任意一个对象的方法(属性)

获得 Class 对象

  //获取Class的方式一
        Person person1 = new Person();
        Class personClass1 = person1.getClass();

        //获取Class的方式二
        Class personClass2 = null;
        try {
            personClass2 = Class.forName("com.lbz.annotationdemo.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //获取Class的方式三
        Class personClass3 = Person.class;

        //获取Class的方式四
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class clazz = classLoader.loadClass("com.lbz.annotationdemo.Person");

判断是否为某个类的实例

一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:

public native boolean isInstance(Object obj);

判断是否为某个类的类型

public boolean isAssignableFrom(Class cls)

创建实例

通过反射来生成对象主要有两种方式。

  • 使用Class对象的newInstance()方法来创建Class对象对应类的实例。

    Class c = String.class; 
    Object str = c.newInstance();
    
  • 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
      //获取String所对应的Class对象 
        Class c = String.class; 
        //获取String类带一个String参数的构造器 
        Constructor constructor = c.getConstructor(String.class);
        //根据构造器创建实例 
        Object obj = constructor.newInstance("23333"); 
        System.out.println(obj);

获取构造器信息

得到构造器的方法

Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的public构造函数(包括父类)
Constructor[] getConstructors() -- 获得类的所有公共构造函数 
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(包括私有)
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)

获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例:

public T newInstance(Object ... initargs)

获取类的成员变量(字段)信息

获得字段信息的方法

Field getField(String name) -- 获得命名的公共字段 
Field[] getFields() -- 获得类的所有公共字段
Field getDeclaredField(String name) -- 获得类声明的命名的字段
Field[] getDeclaredFields() -- 获得类声明的所有字段

调用方法

获得方法信息的方法

Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法 Method[] getMethods() -- 获得类的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法
Method[] getDeclaredMethods() -- 获得类声明的所有方法

当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。 invoke 方法的原型为:

public Object invoke(Object obj, Object... args)

利用反射创建数组

数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference 其中的Array类为

java.lang.reflflect.Array类。我们通过Array.newInstance()创建数组对象,它的原型是:

public static Object newInstance(Class componentType, int length);

反射获取泛型真实类型

当我们对一个泛型类进行反射时,需要的到泛型中的真实数据类型,来完成如json反序列化的操作。此时需要通过 Type 体系来完成。 Type 接口包含了一个实现类(Class)和四个实现接口,他们分别是:

  • TypeVariable

泛型类型变量。可以泛型上下限等信息;

  • ParameterizedType

具体的泛型类型,可以获得元数据中泛型签名类型(泛型真实类型)

  • GenericArrayType

当需要描述的类型是泛型类的数组时,比如List[],Map[],此接口会作为Type的实现。

  • WildcardType

通配符泛型,获得上下限信息;

TypeVariable

class Main {
    K key;
    V value;

    public static void main(String[] args) throws Exception {
        // 获取字段的类型
        Field fk = Main.class.getDeclaredField("key");
        Field fv = Main.class.getDeclaredField("value");

        TypeVariable keyType = (TypeVariable) fk.getGenericType();
        TypeVariable valueType = (TypeVariable) fv.getGenericType();
        // getName 方法
        System.out.println(keyType.getName()); // K
        System.out.println(valueType.getName()); // V
        // getGenericDeclaration 方法
        System.out.println(keyType.getGenericDeclaration());// class com.test.TestType
        System.out.println(valueType.getGenericDeclaration()); // class com.test.TestType
        // getBounds 方法
        System.out.println("K 的上界:"); // 有两个
        for (Type type : keyType.getBounds()) { // interface java.lang.Comparable
            System.out.println(type); // interface java.io.Serializable
        }
        System.out.println("V 的上界:"); // 没明确声明上界的, 默认上界是 Object
        for (Type type : valueType.getBounds()) { // class java.lang.Object
            System.out.println(type);
        }
    }
}




K
V
class Main
class Main
K 的上界:
interface java.lang.Comparable
interface java.io.Serializable
V 的上界:
class java.lang.Object

ParameterizedType

class Main {
    HashMap map;
    public static void main(String[] args) throws Exception {
        Field f = Main.class.getDeclaredField("map");
        System.out.println(f.getGenericType()); // java.util.Map
        ParameterizedType pType = (ParameterizedType) f.getGenericType();
        System.out.println(pType.getRawType()); // interface java.util.Map
        for (Type type : pType.getActualTypeArguments()) {
            System.out.println(type); // 打印两遍: class java.lang.String
        }
    }
}

java.util.HashMap
class java.util.HashMap
class java.lang.String
class java.lang.String

GenericArrayType

class Main {
    List[] lists;
    public static void main(String[] args) throws Exception {
        Field f = Main.class.getDeclaredField("lists");
        GenericArrayType genericType = (GenericArrayType) f.getGenericType();
        System.out.println(genericType.getGenericComponentType());
    }
}


java.util.List

WildcardType

class Main {
    private List a; // 上限
    private List b; //下限
    public static void main(String[] args) throws Exception {
        Field fieldA = Main.class.getDeclaredField("a");
        Field fieldB = Main.class.getDeclaredField("b");
        // 先拿到范型类型
        ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
        ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
        // 再从范型里拿到通配符类型
        WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
        WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
        // 方法测试
        System.out.println(wTypeA.getUpperBounds()[0]); // class java.lang.Number
        System.out.println(wTypeB.getLowerBounds()[0]); // class java.lang.String
        // 看看通配符类型到底是什么, 打印结果为: ? extends java.lang.Number
        System.out.println(wTypeA);
    }
}




class java.lang.Number
class java.lang.String
? extends java.lang.Number

Gson反序列化

在进行GSON反序列化时,存在泛型时,可以借助 TypeToken 获取Type以完成泛型的反序列化。但是为什么TypeToken 要被定义为抽象类呢?

因为只有定义为抽象类或者接口,这样在使用时,需要创建对应的实现类,此时确定泛型类型,编译才能够将泛型signature信息记录到Class元数据中。

动态代理

参考https://juejin.cn/post/6974018412158664734

静态代理

定义

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

目的

  1. 通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性;
  2. 通过代理对象对访问进行控制;

图解

代理模式一般会有三个角色:

WechatIMG145.png

抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口

真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业务逻辑在此。

代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制都放到代理角色中处理!

静态代理缺点

  • 1、重复性: 需要代理的业务或方法越多,重复的模板代码越多;
  • 2、脆弱性: 一旦改动基础接口,代理类也需要同步修改(因为代理类也实现了基础接口)。

动态代理

在运行时再创建代理类和其实例,因此显然效率更低。要完成这个场景,需要在运行期动态创建一个Class。JDK提供了 Proxy 来完成这件事情。基本使用如下:

  1. 创建接口,定义目标列要完成的功能。
  2. 创建目标类实现接口。
  3. 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能。
    1. 调用目标方法
    2. 增强功能
  4. 使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//目标接口
interface Api {
    float test(String a);
}

//目标类
class ApiImpl implements Api {
    @Override
    public float test(String a) {
        System.out.println("目标类中,执行目标方法:" + a);
        return 1F;
    }
}

//必须实现InvocationHandler接口,完成代理类要做的功能(1.调用目标方法 2,功能增强)
class MyInvocationHandler implements InvocationHandler {

    private Object target;

    //动态代理:目标对象是活动的,不是固定的,需要传入进来
    //传入是谁,就给谁创建代理
    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object res;
        res = method.invoke(target, args);//执行目标方法

        if (res != null) {
            Float price = (Float) res;
            price = price + 100;
            res = price;
        }

        //在目标类的方法调用后,你做的其他功能,都是增强的意思
        System.out.println("增强--------------------");

        return res;
    }
}


class Main {
    public static void main(String[] args) {

        //1.创建目标对象
        Api factory = new ApiImpl();

        //2.创建InvocationHandler对象
        InvocationHandler invocationHandler = new MyInvocationHandler(factory);

        //3.创建代理对象
        Api proxy = (Api) Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), invocationHandler);

        //4.通过代理执行方法
        float hello = proxy.test("hello");
        System.out.println("通过动态代理对象,调用方法:" + hello);

    }
}



目标类中,执行目标方法:hello
增强--------------------
通过动态代理对象,调用方法:101.0

实际上, Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class。

动态代理源码分析

本文以jdk提供的Proxy作为分析,Android的实现和jdk的实现大同小异,差别最后再说。

  public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class[] intfs = interfaces.clone();
            //安全管理器.判断有没有创建代理的权限
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 这是动态代理中最重要的方法,代理类就是从中得到的
         */
        Class cl = getProxyClass0(loader, intfs);

        /*
         * 使用我们的InvocationHandler实现类来调用构造方法
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //判断代理类是否是被public修饰的,如果不是,设计代理类是可以通过反射访问到的
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //创建代理类对象
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

为什么动态代理需要传入classLoader?

1⃣️需要校验传入的接口是否可被当前的类加载器加载,假如无法加载,证明这个接口与类加载器不是同一个,按照双亲委派模型,那么类加载层次就被破坏了

2⃣️需要类加载器去根据生成的类的字节码去通过defineClass方法生成类的class文件,也就是说没有类加载的话是无法生成代理类的

我们主要看一下怎么获取到代理类的

 Class cl = getProxyClass0(loader, intfs);
private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // 通过缓存得到代理类,如果没有就通过ProxyClassFactory创建
        return proxyClassCache.get(loader, interfaces);
    }

接下来,我们看看ProxyClassFactory如何创建代理类

    private static final class ProxyClassFactory
        implements BiFunction[], Class>
    {
        // 代理类类名的前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 代理类名字计数器 AtomicLong具有原子性
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class apply(ClassLoader loader, Class[] interfaces) {

            Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class intf : interfaces) {
                /*
                 * 判断相同名字的接口是否是同一个Class对象
                 */
                Class interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * 判断相应接口是否是一个真正的接口
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * 验证接口是否重复
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // 生成的代理类的包名
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * 验证所有非公共接口的包是否在同一个包
             */
            for (Class intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // 如果是公共接口,则用com.sun.proxy包
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * 为代理类生成名字,规则 包名+前缀+数字 例:com.sun.proxy.$Proxy0
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            //生成代理类的二进制文件
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //动态生成代理类,这就是最后一步了,由于是native方法,所以就无法向下追究了
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

接下来我们看一下具体是怎么获取代理类的二进制文件

ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
  public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        //发现可以通过 saveGeneratedFiles参数来决定是否把代理类代存到本地
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

                        //文件写入
                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

        return var4;
    }

发现可以通过 saveGeneratedFiles参数来决定是否把代理类代存到本地,点击它来查看在哪进行设置

    private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));

我们可以把sun.misc.ProxyGenerator.saveGeneratedFiles这个属性设为true来把生成的类保存到本地,再运行,就会看到系统帮我们生成的代理类。以下为部分截取

static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("agent.Massage").getMethod("message", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

在初始化时,获得 method 备用。而这个代理类中所有方法的实现变为:

 public final void message(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

这里的 h 其实就是 InvocationHandler 接口,所以我们在使用动态代理时,传递的 InvocationHandler 就是一个监听,在代理对象上执行方法,都会由这个监听回调出来。

最后用一张图作为总结

1066538-20190916221931929-897879953.png

和Android提供的Proxy对比

        /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;

                return generateProxy(proxyName, interfaces, loader, methodsArray,
                                     exceptionsArray);
            }

可以看到Android并没有通过ProxyGenerator生成代理类对象,而是直接交给native方法去处理。

静态代理和动态代理对比

  • 共同点:两种代理模式实现都在不改动基础对象的前提下,对基础对象进行访问控制和扩展,符合开闭原则。
  • 不同点:静态代理存在重复性和脆弱性的缺点;而动态代理(搭配泛型参数)可以实现了一个代理同时处理 N 种基础接口,一定程度上规避了静态代理的缺点。从原理上讲,静态代理的代理类 Class 文件在编译期生成,而动态代理的代理类 Class 文件在运行时生成,代理类在 coding 阶段并不存在,代理关系直到运行时才确定。

你可能感兴趣的:(注解反射以及动态代理)