美文网首页
Java 反射之动态代理

Java 反射之动态代理

作者: 一个追寻者的故事 | 来源:发表于2020-04-26 14:13 被阅读0次
代理模式

为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为真实对象提供 预处理消息过滤消息传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。

其实就是代理类为被代理类预处理消息、过滤消息并在此之后将消息转发给被代理类,之后还能进行消息的 后置处理。代理类和被代理类通常会存在关联关系,代理类本身不实现服务,而是通过调用被代理类中的方法来提供服务。

代理模式可以大致分为两大部分,一是静态代理,二是动态代理。静态代理中,代理者的代码由程序员 自己 或 通过一些自动化工具生成固定的代码再对其进行编译,也就是说在我们的代码运行前代理类的class 编译文件就已经存在;而动态代理与静态代理相反,通过反射机制动态地生成代理者的对象,也就是说我们在 code 阶段压根就不需要知道代理谁,代理谁我们会在执行阶段决定。

静态代理
动态代理(JDK 中提供的工具)
1、动态代理的使用

Java 提供了一个便捷的动态代理接口 InvocationHandler,还有 Proxy 工具类。

接口类定义:

public interface IPerson {
    public abstract void walk();
}

实体对象定义:

public class Teacher implements IPerson {
    @Override
    public void walk() {
        System.out.println(" walk : a teacher is walking ");
    }
}

动态代理:

public class DynamicProxy implements InvocationHandler {

    //被代理类(真实类)的引用
    Object obj;

    public DynamicProxy(Object obj){
        this.obj = obj;
    }

    // 我们主要通过 invoke 方法来调用具体的被代理类方法,也就是真实的方法。
    //动态代理使我们的代码逻辑更简洁
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("--动态代理:执行真实委托方法之前--");
        Object result = method.invoke(obj, args);
        System.out.println("--动态代理:执行真实委托方法之后--");
        return result;
    }
}

创建代理对象:

    //创建真实对象
    IPerson teacher = new Teacher();
    //动态代理
    DynamicProxy dp = new DynamicProxy(teacher);
    
    /**
        Proxy.newProxyInstance 
    根据指定的接口(一个或多个),返回一个代理对象。分配相关方法执行 到 指定的  InvocationHandler。
  注意:第二个方法参数,必须是接口类型的Class对象
    */
    //创建一个代理对象
    IPerson proxyInstance = (IPerson) Proxy.newProxyInstance(teacher.getClass().getClassLoader(), new Class[]{IPerson.class}, dp);
    //执行方法调用
    proxyInstance.walk();

结果:

--动态代理:执行真实委托方法之前--
 walk : a teacher is walking 
--动态代理:执行真实委托方法之后--
2、动态代理的实现原理

原理: 通过 用户传入的ClassLoader、Class[] interfaces 和 和 InvocationHander 动态生成一个代理类的 Class 对象(这个类型是在运行期间确定的,所以原理上所有的类都可以在运行期间去编写😁)这个代理类 实现了 Class[] interfaces的所有抽象方法 和 Object 的 hashCode、equals 和 toString 方法。 interfaces 中的抽象方法的实现:直接调用 InvocationHandler 中的 invoke 方法。

看一个生成的代理类:

package com.sun.proxy;

import com.lakala.dyProxy.IPerson;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements IPerson {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    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 walk() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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 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);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.lakala.dyProxy.IPerson").getMethod("walk");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
过程

Proxy.newProxyInstance 这个方法会在运行期间动态生成 代理类型的类对象(Class)实例,然后通过反射的方法,创建代理类的实例对象。

时序图

cglib (Code Generation Library)是一个开源项目。 是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。 JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

参考:
https://www.jianshu.com/p/9bcac608c714

相关文章

  • Java基础:反射

    反射注解动态代理相关阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 ...

  • 安卓反射和动态代理的应用

    提纲 java反射基础 反射在Android中的应用 Java动态代理 动态代理在Android的应用 java反...

  • 一文带你搞懂Java反射和动态代理

    分享 Java反射和动态代理

  • Java 动态代理

    前言 关于动态代理 JDK动态代理 CGLIB动态代理 区别 java动态代理是利用反射机制生成一个实现代理接口的...

  • Java反射机制详解(二)

    本篇文章继续介绍Java反射机制,不同的是侧重于介绍动态代理。动态代理是代理模式中的一种,是通过Java反射机制来...

  • Java反射机制总结(二)

    本篇文章继续介绍Java反射机制,不同的是侧重于介绍动态代理。动态代理是代理模式中的一种,是通过Java反射机制来...

  • 快速上手 Kotlin 开发系列之动态代理

    本节介绍 Kotlin 中没有反射的动态代理。 Java 中的动态代理 在讲 Kotlin 的动态代理之前先简单回...

  • Java 反射之动态代理

    代理模式 为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为真实对象提供 预处理消息、过滤消息、传递消...

  • Java 动态代理

    java的动态代理机制详解 JDK动态代理详解 Java核心技术点之动态代理

  • 2021校招 复习总结

    笔记导航: JAVA: 泛型 反射和动态代理 注解 JAVA多线程 ReentrantLock,Volatile,...

网友评论

      本文标题:Java 反射之动态代理

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