Java中的动态代理一

作者: 凯哥Java | 来源:发表于2019-08-26 09:29 被阅读0次

    方法newProxyInstance介绍

    这篇开始学Java中的动态代理部分,刚开始,我们不去了解什么是动态代理相关的概念,除了动态代理,还有静态代理。我们学习动态代理直接从学习一个方法开始,这个方法叫newProxyInstance, 方法有三个参数。

    来源:凯哥Java(kaigejava)

    方法newProxyInstance

    这个方法的作用是:在运行时,动态创建一组指定的接口的实现类对象。动态代理的作用是最终学习AOP, 也就是面向切面编程。面向切面编程和装饰器有点相似,但比装饰器更加灵活。

    JAVA SE JDK API文档打开,搜索Proxy这个类,这个类在java.lang.reflect包下,在反射包下。文档好多描述,概念一开始肯定看不懂,干脆不看好了,直接来看这个动态代理类的方法。

    红圈这个方法就是重点,学习动态代理就只学习这个方法就可以。这个方法的作用就是:在运行时,创建实现了指定一组接口的对象。这个方法有三个参数,指定的而一组接口就是第二个参数,是一个Class数组,接下来具体看看三个参数。

    方法的三个参数

    三个参数,按照顺序分别是 ClassLoader (类加载器),interfaces(一组接口,接口数组),InvocationHandler(调用处理器)。

    ClassLoader (类加载器):

    我们在计算机硬盘写了代码,编译之后,产生字节码文件,例如A.class,这个字节码文件先要加载到JVM内存中才可以跑起来。从硬盘把字节码加载到JVM内存中,需要一个对象去完成这个操作,这个对象就叫ClassLoader (类加载器)。关于类加载,学习完动态代理,我们再来详细学习一下这个知识点。

    接口数组:

    这个参数是一个接口数组,假如我们有接口A和接口B,那么这个参数传进去的写法就是这样 Class[]{A.class, B.class},这个好理解。通过这个方法,得到的代理对象,同时创建了接口A和接口B的具体实现类对象。

    调用处理器:

    调用处理器是一个接口。它的作用是:代理对象的几乎所有方法都会调用InvocationHandler的invoke()方法,其中getClass()方法不执行。

    代码演示

    下面这段代码演示了三个参数如何使用,以及验证了获取这个代理对象转换成指定接口实现类对象,还有证明:代理对象的几乎所有方法都会调用InvocationHandler的invoke()方法。

    package proxy;

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy;

    import org.junit.Test;

    public class Demo1 {

    @Test

    public void fun1() {

    // 1.获取ClassLoader

    ClassLoader loader = this.getClass().getClassLoader();

    // 2.调用处理器

    InvocationHandler handler = new InvocationHandler() {

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    System.out.println("你好,动态代理");

    return null;

    }

    };

    // 3.得到代理对象

    Object o = Proxy.newProxyInstance(loader, new Class[] {A.class, B.class}, handler);

    // 强制转换成A 或者B 类型

    A a = (A) o;

    B b = (B) o;

    // 以下代码证明:代理对象的几乎所有方法都会调用InvocationHandler的invoke()方法

    a.a();

    a.aa();

    b.b();

    b.bb();

    System.out.println(a.getClass());

    }

    }

    interface A {

    public void a();

    public void aa();

    }

    interface B {

    public void b();

    public void bb();

    }

    InvocationHandler和invoke()方法

    详细来看看这个,前面知道InvocationHandler是一个接口,这个接口只有一个方法,那就是invoke()。

    我们开详细看看这个invoke()方法中三个参数和返回值。我们先来在A接口中写一个aaa()方法。

    package proxy;

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy;

    import org.junit.Test;

    public class Demo1 {

    @Test

    public void fun1() {

    // 1.获取ClassLoader

    ClassLoader loader = this.getClass().getClassLoader();

    // 2.调用处理器

    InvocationHandler handler = new InvocationHandler() {

    public Object invoke(Object proxy, Method method, Object[] args)

    throws Throwable {

    System.out.println("你好,动态代理");

    return "xxx";

    }

    };

    // 3.得到代理对象

    Object o = Proxy.newProxyInstance(loader, new Class[] {A.class, B.class}, handler);

    // 强制转换成A 或者B 类型

    A a = (A) o;

    B b = (B) o;

    // 以下代码证明:代理对象的几乎所有方法都会调用InvocationHandler的invoke()方法

    /*

     * a.a(); a.aa(); b.b(); b.bb(); System.out.println(a.getClass());

     */

    Object result = a.aaa("hello", 100);

    System.out.println(result);

    }

    }

    interface A {

    public void a();

    public void aa();

    public Object aaa(String s, int i);

    }

    interface B {

    public void b();

    public void bb();

    }

    运行上面单元测试,输出

    你好,动态代理

    xxx

    为什么会输出xxx呢,我们来看看下面这张图。

    上面这张图,我们来看三个参数和代理对象a调用方法aaa()的一一对应关系。

    Object proxy: 这个就是只代理对象,也就是当前对象,上面代码中a这个对象。

    Method method: 当前被调用的方法,例如aaa()方法

    Object[] args: 实参,例如aaa(“hello”,100), “hello”和100就是实参。

    联系凯哥--》凯哥Java(kaigejava)

    这三个参数,在代码运行中会自动作为参数传入,最终调用的就是invoke()方法,返回什么取决于,invoke()方法中的返回值。

    相关文章

      网友评论

        本文标题:Java中的动态代理一

        本文链接:https://www.haomeiwen.com/subject/kgnlectx.html