likes
comments
collection
share

搞懂Java反射和JDK里的动态代理

作者站长头像
站长
· 阅读数 5

前言

动态代理模式,也是Java中常见的一种设计模式,其中动态代理模式,也是用到了反射,所以我们反射和动态代理一起学一学

一、了解反射

反射看名字很高大上哈,其实搞明白了也很简单,反射之中包括了一个反字,所以了解反射我们先从正开始,正常情况下呢,我们调用一个类来做方法的时候,是从main方法里声明一个,然后再实例化这个类,然后再调用里面的方法

public class RefleDemo {
    public static void main(String[] args) {
    	//实例化对象的标准用法,也就是所谓的正
        Servant servant=new Servant();
        servant.service("Hello");
    }
}

反射则是一开始并不知道我要初始化对象它是什么类,自然也就无法使用new 关键字来创建对象了,这时候,我们使用JDK提供的反射API进行反射调用,这时候小伙伴们可能就有疑问,什么情况下,我们不知道我们要初始化的类是什么呢? 各种框架,比如说我们Android中使用了动态代理的网络通讯的框架Retrofit

   Class servantRefle=Class.forName("rfle.Servant");
   Servant servantClass= (Servant) servantRefle.newInstance();
   servantClass.service("hello");

反射就是在运行的时候才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法 反射是Java被视为动态语言的关键,根据反射我们可以根据类信息,操作类中的所有方法和属性

二、继续了解反射(哈哈哈)

1. 每一个类对应的class放在哪里?

大家都知道,Java语音是一个面向对象的语言,在面向对象的世界里,万事万物皆对象,那我们写的class类是不是对象呢,是的,他们都是 java.lang.Class 的对象 搞懂Java反射和JDK里的动态代理 我们写的每一个类,都是这个Class它的一个对象,我们在写类的时候,并没有显式的写这个对象,那么它放在哪里了呢,我们都知道,我们运行的时候,我们写的类会编译成一个类,生成一个class文件,而编译器就把Class的这个对象存放在class文件的末尾,里面保存了类的元数据信息,这些元数据信息都包括什么呢? ``

2. 这个class里面都保存了什么

保存了类的所有信息,比如它是类还是接口 集成 和实现了那些类和接口,有什么属性 ,有什么方法 我们在new一个对象的时候,可以new 很多对象,但是这个类生成的class对象只能有一个(在不同的类加载器,可能有多个,这里涉及到虚拟机的知识了,emmm...) 我们在实例化Servant这个的类对象的时候,虚拟机会去检查,在虚拟机里面,这个类有没有被加载过,如果没有,虚拟机会先加载Servant对应的这个class对象,加载完之后,才会轮到Servant实例化本身的对象

3. 如何使用?

我们怎么获取这个Class 对象呢? 我们有好几种方法

  • 通过类名获取
      Class servantClass1=Servant.class;
  • 通过实例来获取
		Servant servant=new Servant();
        servant.service("Hello");
        Class servantClass2=servant.getClass();
  • 通过这个类的全限定名称 (包名+这个类的类名)Class.forName来获取
 		Class servantRefle=Class.forName("rfle.Servant");

前面两种获取Class 的方式,都得需要确切的知道Servant是存在的有的,对于各种框架来说,它们常用的是第三种方式来获取Class 对象 获取了这个Class 对象,我们就可以做很多很多事情,能做什么呢 比如获取 Servant的实例,

  			Class servantRefle=Class.forName("rfle.Servant");
            Servant servantClass= (Servant) servantRefle.newInstance();
            servantClass.service("hello");

但是单单获取实例远远不够滴,

3.1 获取类加载器

package rfle;
public class TestClassLoader {
    public static void testClassLoader() throws ClassNotFoundException {
        //1、获取一个系统的类加载器(可以获取,当前这个类就是它加载的)
        ClassLoader classLoader=ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);
        //2丶获取系统类加载器的父类加载器(扩展加载器,可以获取)
        classLoader=classLoader.getParent();
        System.out.println(classLoader);
        //3丶获取扩展类加载器(引导类加载器,不可获取)
        classLoader=classLoader.getParent();
        System.out.println(classLoader);
        //4、测试当前类是那个类加载器加载的(系统加载器)
        classLoader=Class.forName("rfle.RelectionTest").getClassLoader();
        System.out.println(classLoader);
        //5、测试JDK提供的Object类 由那个类加载器加载的(引导类)
        classLoader=Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);
    }
}
package rfle;

public class RelectionTest {
    public static void main(String[] args) throws ClassNotFoundException {
        TestClassLoader.testClassLoader();
    }
}

运行结果

搞懂Java反射和JDK里的动态代理

3.2 获取构造器对象

这是一个Person类

public class Person {
    String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
         System.out.println("this is setName");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        System.out.println("this is setAge");
    }
    }

    /***
     * 包含一个带参的构造方法和不带参的构造方法
     * @param name
     * @param age
     */
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }
        //私有方法
    private void  privateMethod(){
        System.out.println("这是一个私有方法");
    }
}
  
  public static void testConstructor() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        String className="rfle.Person";
        Class<Person> clazz= (Class<Person>) Class.forName(className);
        System.out.println("获取全部Constructor对象-----");
        Constructor<Person>[] constructors= (Constructor<Person>[]) clazz.getConstructors();
        for (Constructor<Person> constructor:constructors) {
            System.out.println(constructor);
        }
        System.out.println("获取某一个Constructor对象 需要参数列表----");
        Constructor<Person> constructor= clazz.getConstructor(String.class,int.class);
        System.out.println(constructor);

        System.out.println("调用Constructor的newInstance方法创建对象----");
        Person person1= constructor.newInstance("赵Sir",18);
        System.out.println(person1.getName());
    }

运行结果 搞懂Java反射和JDK里的动态代理 这里需要说一下因为我们的构造方法的参数类型是int型的,所以我们再获取构造器的时候传入的参数一定是int.class 而不能是Integer.class,不然会报没有找到方法异常

3.3 获取方法并执行相对应的方法

public class TestMethod {
/**
 * 方法相关
 */
    public void testMethod() throws  Exception{
        String className="rfle.Person";
        Class clazz=Class.forName(className);
        System.out.println("获取clazz对应类中的所有方法," +
                "不能获取private方法,且获取从父类继承来的所有方法");
        Method[] methods= clazz.getMethods();
        for (Method method:methods) {
            System.out.println(method.getName()+"()");
        }
        System.out.println("__________________________________");
        System.out.println("获取所有方法,包括私有方法" +
                "所有声明的方法,且获取当前类方法");
        methods= clazz.getDeclaredMethods();
        for (Method method:methods) {
            System.out.println(method.getName()+"()");
        }
        System.out.println("__________________________________");
        System.out.println("获取指定方法,和获取构造器的差不多,需要方法名称 和参数列表 无参则不写");
        Method method=clazz.getDeclaredMethod("setName",String.class);
        System.out.println(method);
        method=clazz.getDeclaredMethod("setAge",int.class);
        System.out.println(method);
        System.out.println("__________________________________");
        System.out.println("执行我们获取的方法");
        Object object=clazz.newInstance();
        //第一个参数 这个方法所在类的实例,可变参数 参数列表
        method.invoke(object,18);
        System.out.println("__________________________________");
        System.out.println("执行私有方法—");
        method=clazz.getDeclaredMethod("privateMethod");
        //在执行私有方法之前 一定要 执行这句代码。把Accessible设成true
        method.setAccessible(true);
        method.invoke(object);

    }
}

运行结果 搞懂Java反射和JDK里的动态代理 执行私有方法的时候一定要注意,一定要在执行之前,将Accessible设成true,不仅是方法,访问私有域的时候也得设置一下

3.4 通过反射访问成员变量

public class TestFiled {
    /***
     * 域相关
     */
    public void testFiled() throws Exception{
        String className="rfle.Person";
        Class clazz=Class.forName(className);
        System.out.println("获取共有和私有的所有字段,但不能获取父类字段");
        Field[] fields= clazz.getDeclaredFields();
        for (Field field:fields) {
            System.out.println(field.getName());
        }
        System.out.println("__________________________________");
        System.out.println("获取指定字段");
        Field field=clazz.getDeclaredField("name");
        System.out.println(field.getName());

        System.out.println("__________________________________");
        System.out.println("获取指定字段的值");
        Person person=new Person("铭儿",18);
        //第一个参数 这个方法所在类的实例
        Object object= field.get(person);
        System.out.println(field.getName()+"="+object);
        System.out.println("__________________________________");
        System.out.println("设置指定对象的值");
        field.set(person,"小铭同学");
        System.out.println(field.getName()+"="+person.getName());
        //访问私有字段
        field=clazz.getDeclaredField("age");
        field.setAccessible(true);
        field.get(person);
        field.set(person,20);
        System.out.println(field.getName()+"="+person.getAge());
    }
}

运行结果 搞懂Java反射和JDK里的动态代理 反射很强大,它很灵活,可以突破权限修饰符直接进行访问,所以使用的时候一定要小心 因为反射是在运行的时候,临时创建的类,在调用的效率上肯定比我们new的时候要慢

三、动态代理模式

1.静态代理模式

定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用 目的:

  1. 通过引入代理对象方式,来间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性
  2. 通过代理对象对原有的业务增强 通俗点讲所谓的代理对象就相当于,我们日常生活中的中介 搞懂Java反射和JDK里的动态代理 用品公司,就是目标对象,mark代购就是代理对象,张三 就是访问着,代理不单单提供工厂的售卖服务,还提供售前咨询,售后服务等等,但是用代码怎么实现呢 搞懂Java反射和JDK里的动态代理 目标对象和 代理对象都要实现一个共同的接口服务 代理对象 包含目标对象 我们用代码实现一下这种模式
 /***
 * 代理对象 和工厂共同的业务接口
 */
public interface ManToolsFactory {
    void saleManTools(String size);
}

/***
 * 目标对象 工厂
 */
public class AaFactory implements  ManToolsFactory{
    @Override
    public void saleManTools(String size) {
        System.out.println("按需求定制了一个size为"+size+"的女model");
    }
}
/***
 * 代理对象 mark
 */
public class Mark implements ManToolsFactory {
    public Mark(ManToolsFactory manToolsFactory) {
        this.manToolsFactory = manToolsFactory;
    }

    public  ManToolsFactory manToolsFactory;
    @Override
    public void saleManTools(String size) {
        doSthBefore();
        manToolsFactory.saleManTools(size);
        doSthAfter();
    }

    /***
     * 后置处理器
     */
    private void doSthAfter(){
        System.out.println("精美包装,快递一条龙服务");
    }

    /***
     * 前置处理器
     */
    private  void doSthBefore(){
    
        System.out.println("根据需求进行市场调研和产品分析");
      
    }
}
/***
*张三
*/
public class Client {
    public static void main(String[] args) {
        //静态代理模式
        ManToolsFactory factory=new AaFactory();
        Mark mark=new Mark(factory);
        mark.saleManTools("D");
    }
}

这样的话,张三和工厂没有任何联系,而是通过mark这个代理买来了要给size是D的女model 这就是静态代理模式,因为真实对象,和代理对象是一对一存在的 静态代理模式有什么缺点呢 违反开闭原则:扩展能力差,可维护性差

2. 动态代理模式

业务扩展了,多了一个张三的老婆 ,张三和张三的老婆要求肯定是不一样的,都是好朋友 不都得帮忙 搞懂Java反射和JDK里的动态代理 他们的需求不一样,人也不一样,怎么办呢,如果用静态代理维护,要么Mark再添加一个业务,女人用品的服务 要么把他推荐给更懂女人的Alvin


public class Alvin implements WomanToolsFactory {
    public  WomanToolsFactory womanToolsFactory;
    @Override
    public void saleWomenTools(float length) {
        womanToolsFactory.saleWomenTools(length);
    }

    /***
     * 后置处理器
     */
    private void doSthAfter(){
        System.out.println("精美包装,快递一条龙服务");
    }

    /***
     * 前置处理器
     */
    private  void doSthBefore(){

        System.out.println("根据需求进行市场调研和产品分析");

    }
}

按同样的流程走一遍,如果业务全包给mark,每次增加一个业务是不是都得更改mark,这就违反了开闭原则(对修改关闭,对新增开放) 搞懂Java反射和JDK里的动态代理 搞懂Java反射和JDK里的动态代理

这个海外代购公司,就是动态的生成代理,张三来了就安排mark去接待,他老婆来了就派Avlin去接待

搞懂Java反射和JDK里的动态代理

/***
 * Mark代购公司
 */
public class MarkCompany implements InvocationHandler {
    /***
     * 持有真实对象
     */
    private Object factory;

    public Object getFactory() {
        return factory;
    }

    public void setFactory(Object factory) {
        this.factory = factory;
    }
    /***
     * 通过Proxy获取动态代理对象
     */
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(factory.getClass().getClassLoader(),
        factory.getClass().getInterfaces(),this);
    }
    /***
     * 通过动态代理对象方法进行增强
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doSthBefore();
        Object result =method.invoke(factory,args);
        doSthAfter();
        return result;
    }
    /***
     * 后置处理器
     */
    private void doSthAfter(){
        System.out.println("精美包装,快递一条龙服务");
    }

    /***
     * 前置处理器
     */
    private  void doSthBefore(){

        System.out.println("根据需求进行市场调研和产品分析");

    }


}

public class Client {
    public static void main(String[] args) {
        //静态代理模式
        ManToolsFactory factory=new AaFactory();
        Mark mark=new Mark(factory);
        mark.saleManTools("D");
        //动态代理模式
        ManToolsFactory aaToolsFactory=new AaFactory();
        MarkCompany markCompany=new MarkCompany();
        markCompany.setFactory(aaToolsFactory);
        //张三来了
        ManToolsFactory emploee1= (ManToolsFactory) markCompany.getProxyInstance();
        emploee1.saleManTools("E");
        //张三老婆来了
        WomanToolsFactory bbToolsFactory=new BbFactory();
        markCompany.setFactory(bbToolsFactory);
        WomanToolsFactory emploee2= (WomanToolsFactory) markCompany.getProxyInstance();
        emploee2.saleWomenTools(1.8f);
		//我们再编码过程中没有声明任何代理类就完成了两次 海外代购
    }
}

这样就可以动态的生成代理类了,无需再去声明Mark和Alvin了,同样的完成了海外代购服务

3.Proxy是怎么帮助我们生成的代理类的呢?

我们debug的时候看一下啊 emploee的信息 搞懂Java反射和JDK里的动态代理 在后边的类信息里,emplyee1 是、$Proxy0 这个就是jdk为我们生成的代理对象,$Proxy0 是怎么生成的呢,了解这一个问题之前 先了解一下类的生命周期搞懂Java反射和JDK里的动态代理 看我们在生成动态代理的时候,是没有走编写java源文件这一步的,jdk是怎么实现的呢 在Proxy的newProxyInstance方法里 搞懂Java反射和JDK里的动态代理 看我画圈圈的地方Class Class什么,前面我们说了是每个类的对应的class对象,这个肯定是有用的,然后接着往下看 搞懂Java反射和JDK里的动态代理 然后拿到了这个类的构造方法,返回了 cl对应类的一个实例,然后我们继续去看这个cl是怎么生成的去看getProxyClass0这个方法 搞懂Java反射和JDK里的动态代理 看到这个代码,发现了一个规矩好像,在实现接口的时候,接口数不能超过65535,字节码里有这个存储接口数量的正好占四个字节,刚好不能超过这个数 然后我们再看return 看变量名proxyClassCache,说明jdk在生成动态代理的时候是做了缓存的,既然是有缓存,第一次生成的的时候肯定不存在啊,那我们就接着去看get的实现,在get方法里我们发现真正创建代理类的方法是这个方法 搞懂Java反射和JDK里的动态代理 接着往下走去看apply,我们会发现 apply是一个泛型接口, 搞懂Java反射和JDK里的动态代理 我们goto impl正好发现了一个实现类 搞懂Java反射和JDK里的动态代理 跟着这个思路走,去看这个实现类里这个方法,我们好像又发现了点什么 搞懂Java反射和JDK里的动态代理

它吧我们的代理类生成了字节码然后存在了byte里了,我们再看看proxyname 搞懂Java反射和JDK里的动态代理 哎呀,正好和我们debug出来的一样,后边加了个 long 进行cas自增的一个num.,为了验证是不是递增的我再debug一下把emplee2也看一下 搞懂Java反射和JDK里的动态代理 ProxyGenerator.generateProxyClass()这个方法就是 传进去的class信息,然后根据class信息,去实现 这个接口的实现类的字节码,然后通过defineClass0这个方法返回一个class 但是我们点进去 发现是一个native方法,那我们想个办法 看一看这个生成的代理类到底是啥,我们把生成的byte数组写到一个文件里,然后再用反编译工具 反编译一下看看 到底是个什么东西

public class ProxyUtils {
    public static void generateClassFile(Class clazz,String proxyName){
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, new Class[]{clazz});
        String paths=clazz.getResource(".").getPath();
        FileOutputStream out=null;
        try {
        out=new FileOutputStream(paths+proxyName+".class");
        out.write(proxyClassFile);

            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

调用

        //动态代理模式
        ManToolsFactory aaToolsFactory=new AaFactory();
        MarkCompany markCompany=new MarkCompany();
        markCompany.setFactory(aaToolsFactory);
        //张三来了
        ManToolsFactory emploee1= (ManToolsFactory) markCompany.getProxyInstance();
        emploee1.saleManTools("E");
        //张三老婆来了
        WomanToolsFactory bbToolsFactory=new BbFactory();
        markCompany.setFactory(bbToolsFactory);
        WomanToolsFactory emploee2= (WomanToolsFactory) markCompany.getProxyInstance();
        emploee2.saleWomenTools(1.8f);
        ProxyUtils.generateClassFile(aaToolsFactory.getClass(),emploee1.getClass().getSimpleName());
        ProxyUtils.generateClassFile(bbToolsFactory.getClass(),emploee2.getClass().getSimpleName());

反编译之后的结果

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.AaFactory;

public final class $Proxy0 extends Proxy implements AaFactory {
    private static Method m1;
    private static Method m8;
    private static Method m3;
    private static Method m2;
    private static Method m6;
    private static Method m5;
    private static Method m7;
    private static Method m9;
    private static Method m0;
    private static Method m4;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void notify() throws  {
        try {
            super.h.invoke(this, m8, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void saleManTools(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);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait(long var1) throws InterruptedException {
        try {
            super.h.invoke(this, m6, new Object[]{var1});
        } catch (RuntimeException | InterruptedException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void wait(long var1, int var3) throws InterruptedException {
        try {
            super.h.invoke(this, m5, new Object[]{var1, var3});
        } catch (RuntimeException | InterruptedException | Error var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new UndeclaredThrowableException(var6);
        }
    }

    public final Class getClass() throws  {
        try {
            return (Class)super.h.invoke(this, m7, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void notifyAll() throws  {
        try {
            super.h.invoke(this, m9, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait() throws InterruptedException {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | InterruptedException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m8 = Class.forName("proxy.AaFactory").getMethod("notify");
            m3 = Class.forName("proxy.AaFactory").getMethod("saleManTools", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m6 = Class.forName("proxy.AaFactory").getMethod("wait", Long.TYPE);
            m5 = Class.forName("proxy.AaFactory").getMethod("wait", Long.TYPE, Integer.TYPE);
            m7 = Class.forName("proxy.AaFactory").getMethod("getClass");
            m9 = Class.forName("proxy.AaFactory").getMethod("notifyAll");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m4 = Class.forName("proxy.AaFactory").getMethod("wait");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

所有的代理类都继承了 Proxy,看反编译结果 是不是实现了我们的业务接口AaFactory,是不是满足了我们前面所说的不管是代理对象还是真实对象,都得共同实现一个业务接口,接着往下看 我们看到了一个熟悉的方法saleManTools(),里面执行了一个 h.invoke(this, m3, new Object[]{var1}); h是谁呢 这个文件里没有,肯定是再父类里面,我们去找找

搞懂Java反射和JDK里的动态代理 我去,这个h不就是我们在写动态代理传进去的InvocationHandler么,它的invoke方法不就是 搞懂Java反射和JDK里的动态代理 this,就是代理对象了,m3是啥?我们继续找m3 搞懂Java反射和JDK里的动态代理 看到这里可能,有同学会懵逼,我第一遍也懵来着,总结一下 1、MarkCompany 实现了 InvocationHandler 2丶调用MarkCompany getProxyInstance的时候将业务接口的Class信息传给Proxy.newProxyInstance() 3、newProxyInstance利用反射生成一个 $Proxy+number的一个类 4,newProxyInstance,生成一个代理类的实例 将InvocationHandler 也就是MarkCompany传进去 5、调用这个代理类的实例的 saleManTools方法 ,也就调用了InvocationHandler 也就是MarkCompany 的invoke方法,完成了代理的对象方法的增强

总结

上边就是反射和动态代理的相关知识,从源码入手分析了一下Jdk动态代理对象是怎么生成的,写的有什么不对的请大佬们多多赐教!希望大佬们一键三连!

转载自:https://juejin.cn/post/6926090916939694088
评论
请登录