代理模式(静态代理、JDK动态代理)Java实现

本文详细介绍了代理模式的概念和作用,包括静态代理和JDK动态代理的实现方式。静态代理通过预先定义接口或继承父类实现,动态代理则在运行时动态生成代理类。文中通过代码示例展示了如何在真实主题前后添加处理逻辑,并解释了JDK动态代理中代理对象调用方法时为何会执行InvocationHandler的invoke方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理模式概述

在有些情况下,一个对象不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。

代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

模式的结构

代理模式的主要角色如下:

  1. 抽象主题:通过接口或抽象类声明被代理对象和代理对象实现的业务方法。
  2. 真实主题:实现了抽象主题中的具体业务,是代理对象要代理的真实对象,是最终要引用的目标对象。
  3. 代理类:访问、控制或扩展真实主题的功能。

在代码中,代理一般会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。

根据代理类的创建时期,代理模式分为静态代理和动态代理。

  • 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。

  • 动态:在程序运行时,运用反射机制动态创建代理类的 .class文件

静态代理

使用静态代理时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。

代码演示:

//抽象主题
interface AbstractSubject {
    void operate();
}

//真实主题
class RealSubject implements AbstractSubject {

    @Override
    public void operate() {
        System.out.println("真实主题的处理方法...");
    }
}

//静态代理类
class Proxy implements AbstractSubject {
    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    /**
     * 代理类的operate方法,可以在真实对象的operate方法前后增加处理逻辑
     */
    @Override
    public void operate() {
        beforeOperate();
        realSubject.operate();
        afterOperate();
    }

    private void beforeOperate() {
        System.out.println("operate方法的预处理");
    }

    private void afterOperate() {
        System.out.println("operate方法的后置处理");
    }
}

//访问类
public class Client {
    public static void main(String[] args) {
        Proxy proxy = new Proxy(new RealSubject());
        proxy.operate();
    }
}

动态代理

JDK动态代理

使用JDK动态代理时,目标对象要实现接口,代理类由 JDK 的API 在程序运行时在内存中动态创建

JDK 中生成代理对象的API:

代理类所在包:java.lang.reflect.Proxy,生成代理对象的方法:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

方法参数说明:

  • ClassLoader loader:被代理类的类加载器

  • Class<?>[] interfaces:被代理类的实现的所有接口

  • InvocationHandler h:代理实例的调用处理程序实现的接口,每个代理实例都有一个关联的调用处理程序。在代理实例上调用方法时,该方法调用将被编码并分派到其调用处理程序的invoke方法。源码:

    package java.lang.reflect;
    
    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    

    invoke方法参数说明:

    • Object proxy:代理实例
    • Method method:代理实例调用的方法对应的 Method 实例
    • Object[] args:代理实例调用的方法的参数值的对象数组

    invoke方法返回值:代理实例的方法调用返回的值,若代理实例的方法无返回值,则返回null

代码演示:

//抽象主题
interface AbstractSubject {
    int operate(int a, int b);
}

//真实主题
class RealSubject implements AbstractSubject {

    @Override
    public int operate(int a, int b) {
        System.out.println("真实主题的处理方法...");
        return a + b;
    }
}

//访问类
public class Client {
    public static void main(String[] args) {
        //创建目标对象(被代理对象)
        RealSubject realSubject = new RealSubject();

        //设置保存运行期生成的jdk动态代理类的class文件
        //System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        //生成代理对象
        AbstractSubject proxy = (AbstractSubject) Proxy.newProxyInstance(
                RealSubject.class.getClassLoader(),
                RealSubject.class.getInterfaces(),
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //增加前置处理
                beforeOperate();

                //调用operate方法
                Object obj = method.invoke(realSubject, args);

                //遍历operate方法实参
                for (int i = 0; i < args.length; i++) {
                    System.out.println("第" + i + "个参数:" + args[i]);
                }

                //增加后置处理
                afterOperate();

                return obj;
            }
        });

        //代理对象调用operate方法,间接访问目标对象
        int value = proxy.operate(5, 10);
        System.out.println("operate方法的返回值:" + value);
    }

    //前置处理逻辑
    private static void beforeOperate() {
        System.out.println("operate方法的预处理");
    }

    //后置处理逻辑
    private static void afterOperate() {
        System.out.println("operate方法的后置处理");
    }
}

运行结果:

operate方法的预处理
真实主题的处理方法...
第0个参数:5
第1个参数:10
operate方法的后置处理
operate方法的返回值:15

问题:代理对象proxy调用operate方法为何会执行InvocationHandler接口实现类的invoke方法?

可以通过分析运行时生成的代理对象对应的代理类得知,在main方法里生成代理对象代码前,增加下面代码,用于设置保存在程序运行期生成的jdk动态代理类的class文件:

//Java8设置保存在程序运行期生成的jdk动态代理类的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

IntelliJ IDEA自动反编译出的代理类如下,从代码中可以知道:生成的代理类继承java.lang.reflect.Proxy类,实现了AbstractSubject抽象主题接口,上面生成的代理对象proxy就是类 P r o x y 0 的 实 例 。 程 序 运 行 调 用 代 理 类 Proxy0的实例。程序运行调用代理类 Proxy0Proxy0 的构造器 public P r o x y 0 ( I n v o c a t i o n H a n d l e r v a r 1 ) 时 会 调 用 父 类 构 造 器 , 传 入 I n v o c a t i o n H a n d l e r 接 口 的 实 现 类 对 象 。 代 理 类 Proxy0(InvocationHandler var1) 时会调用父类构造器,传入InvocationHandler接口的实现类对象。代理类 Proxy0(InvocationHandlervar1)InvocationHandlerProxy0的operate方法中有这样一句调用代码:super.h.invoke(this, m3, new Object[]{var1, var2}),因此会执行InvocationHandler接口的实现类的invoke方法,这里的 this 即代理对象proxy,m3即operate方法的method实例,var1、var2即调用operate方法传入的实参5和10。

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

package v4;

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

final class $Proxy0 extends Proxy implements AbstractSubject {
    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 int operate(int var1, int var2) throws  {
        try {
            return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    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("v4.AbstractSubject").getMethod("operate", Integer.TYPE, Integer.TYPE);
            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());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值