Java动态代理的实现机制

一、概述

代理是一种设计模式,其目的是为某对象提供一个代理以控制对该对象的访问,代理类负责为被代理类处理消息,过滤消息以及后续处理。为了保持行为的一致性,代理类和被代理类通常会实现相同的接口。

按照代理的创建时期,代理可以分为两种:

  • 静态代理:由程序员创建代理类,也就是说在程序运行期代理类的.class文件就已经存在。
  • 动态代理:在程序运行时运行反射机制动态创建生成代理类

在介绍动态代理之前我们先简单介绍一下静态代理。

二、静态代理

上面说过,代理类和被代理类一般都要实现相同的接口,我们定义一个这样的接口如下:

public interface Service {
    public void add();
}

被代理类作为接口的一种实现,定义如下:

public class ServiceImpl implements Service {

    @Override
    public void add() {
        System.out.println("添加用户!");
    }
}

假如我们要求被代理类加一些日志操作,代理类就可以做如下定义:

public class ServiceProxy implements Service {
    private Service service;

    public ServiceProxy(Service service) {
        this.service = service;
    }

    @Override
    public void add() {
        System.out.println("服务开始");
        service.add();
        System.out.println("服务结束");
    }
}

编写测试类:

public class TestMain {

    public static void main(String[] args) {
        //创建被代理对象
        Service service = new ServiceImpl();
        //使用被代理对象来创建代理对象
        Service proxy = new ServiceProxy(service);
        //执行方法
        proxy.add();
    }
}

运行测试程序,打印结果如下:

从上面的代理可以看到,静态代理类只能为特定的接口服务,如果要服务多类型的对象,就要为每一种对象进行代理。我们就会想是否可以通过一个代理类完成全部的代理功能,于是引入了动态代理的功能。

三、动态代理

Java的动态代理主要涉及两个类,Proxy和InvocationHandler。

Proxy: 提供了一组静态方法来为一组接口动态地生成代理类及其对象。

//该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy);
//该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces);
//该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl);
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);

InvocationHandler: 它是调用处理器接口,自定义一个invoke方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对被代理类的代理访问

//该方法负责集中处理动态代理类上所有方法调用
//第一个参数是代理类实例
//第二个参数是被调用的方法对象
//第三个参数是方法的调用参数
//调用处理器根据这三个参数进行预处理或者分派到被代理类实例上反射执行
Object invoke(Object proxy, Method method, Object[] args);

实现Java的动态代理,具体有以下四个步骤:

1. 通过实现InvocationHandler接口创建自己的调用处理器

2. 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类

3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器类接口类型

4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入

下面根据这四个步骤来实现自己的动态代理实例:

接口和接口的实现类(被代理类)跟上面静态代理的代码是一样,这里我们来实现InvocationHandler接口创建自己的调用处理器

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ServiceHandler implements InvocationHandler {
    private Object o;
    public ServiceHandler(Object o) {
        this.o = o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("服务开始");
        //invoke表示对带有指定参数的指定对象调用由此Method对象表示的底层方法
        Object result = method.invoke(o, args);
        System.out.println("服务结束");
        return result;
    }
}

编写测试类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class TestMain {

    public static void main(String[] args) {
        // 创建被代理对象
        Service service = new ServiceImpl();
        InvocationHandler handler = new ServiceHandler(service);
        Service s = (Service) Proxy.newProxyInstance(service.getClass().getClassLoader(),
                service.getClass().getInterfaces(), handler);
        s.add();
    }
}

 运行测试程序,打印结果跟静态代理打印的结果是一样的。

我们从上述代码并没有看到之前说的步骤中的2和3,这是因为Proxy的静态方法newProxyInstace已经为我们封装了这两个步骤:

//通过Proxy为包括Interface接口在内的一组接口动态创建代理类的Class对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[]{Interface.class, ...});
//通过反射从生成的Class对象中获取构造函数对象
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
//通过构造函数对象创建动态代理类的实例
Interface proxy = constructor.newInstance(new Object[]{handler});

newProxyInstance函数的内部实现为:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException {
    //检查h不为空,否则抛异常
    Objects.requireNonNull(h);
    //获得与指定类装载器和一组接口相关的代理类的Class对象
    final Class<?>[] intfs = interfaces.clone();
    //检查接口的Class对象是否对类装载器可见,并且与类装载器所能识别的接口的Class对象是完全相同的
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
    //获得与指定类装载器和一组接口相关的代理类的Class对象
    Class<?> cl = getProxyClass0(loader, intfs);

    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        //通过反射获取构造函数对象并生成代理类实例
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                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);
    }
}

五、总结

1、所谓的动态代理就是这样一种class,它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface,但是它其实并不会替你作任何实质性的工作,而是根据你在生成实例时提供的参数handler,由这个handler来接管实际的工作。

2、Proxy的设计使得它只能支持interface的代理,Java的继承机制注定了动态代理类无法实现对class的动态代理,因为多继承在Java中本质上就行不通。

原文地址:https://www.cnblogs.com/africancu/p/10383581.html

时间: 2024-10-14 05:22:53

Java动态代理的实现机制的相关文章

深入理解java动态代理的实现机制

今天将从以下5方面来系统的学习一下java动态代理的实现机制: 什么是代理 什么是静态代理 什么是动态代理 动态代理的实现机制 动态代理的使用场景 1,什么是代理 相信大家都有购买过火车票或者机票的经历,有的人在携程买,有的在飞猪,也有的在微信上买等等,这里的携程飞猪微信也好都是受铁路部的委托代理售卖火车票,这里的携程飞猪就是代理类,铁路部就是委托类,这就是代理 2,什么是静态代理 所谓的静态代理就是在代码运行之前,代理类就已经存在,通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生

Java 动态代理机制分析及扩展,第 1 部分

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 回页首 代理:设计模式 代理是一种常用的设计

Java 动态代理机制分析及扩展

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其

[转]Java 动态代理机制分析及扩展

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其

理解java动态代理

java动态代理是java语言的一项高级特性.在平时的项目开发中,可能很难遇到动态代理的案例.但是动态代理在很多框架中起着不可替代的作用,例如Spring的AOP.今天我们就聊一聊java动态代理的实现原理. jdk对于动态代理的支持主要依赖于两个类:Proxy和InvocationHandler.我们先看一下类图. Subject类是主题类,定义了我要做什么.我们需要代理的类即实现Subject接口的RealSubject. 1.InvocationHandler InvocationHand

java动态代理机制

首先了解代理设计模式,其思想是为其他对象提供一种代理以控制对这个对象的访问. java动态代理就是遵循这种思想,spring中的AOP实现原理就是java的动态代理. 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的. 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通

Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

作者:亦山 推荐:hh375的图书馆 class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class 文件内的信息,生成对应的 Class对象: class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的.具体class文件是怎样组织类信息的,可以参考 此博文:深入理解Java Class文件格式系列.或者

Java 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class 文件内的信息,生成对应的 Class对象: class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的.具体class文件是怎样组织类信息的,可以参考 此博文:深入理解Java Class文件格式系列.或者是Java虚拟机规范. 下面通过一段代

Java中的动态代理及反射机制

面向对象的基本原则封装.继承.多态,在java中多态机制,表现为变量多态,方法多态,这都是指的是因对象所属的类不同,而调用不同的类方法:对于对象的方法,还有函数重载,java中的函数的签名是由函数名+参数方法来定的,不能仅由返回值不同来定. 反射Reflect 运行时获取类的类型,域,方法等各种属性. Class是一个类,其实例对应其他不同分 (CalculatorImpl)Class.forName("CalculatorImpl").newInstance(); newInstan