深入理解代理模式

代理模式是一种常见的设计模式,它在许多场景中都有广泛的应用。在本文中,我们将深入探讨代理模式的应用场景和实现原理,以及静态代理和动态代理之间的区别。此外,我们还会比较CGLib和JDK Proxy代理的差异,并提供相应的代码示例。

应用场景和实现原理

代理模式的主要作用是为其他对象提供一个代理以控制对这个对象的访问。这种控制的形式可以是在访问前进行一些预处理或过滤,也可以是在访问后进行一些额外的操作。在软件开发中,代理模式常被用于实现以下情况:

  1. 远程代理:为了实现远程方法调用,可以使用代理模式来隐藏底层通信细节,在本地代理对象的方法中进行远程通信。
  2. 虚拟代理:在创建对象时,代理模式可以通过使用一个轻量级的代理对象来代替真实对象,从而减少开销。
  3. 安全代理:代理模式可以用来控制对对象的访问权限,确保只有具有足够权限的用户才能访问对象。

代理模式的实现原理是通过创建一个代理类,该类具有与被代理类相同的接口,以便能够向客户端提供相同的服务。代理类中包含一个指向真实对象的引用,并在其方法中调用真实对象的相应方法。这样,客户端可以通过代理对象来访问真实对象,而无需直接与真实对象进行交互。

静态代理和动态代理的区别

  • 静态代理是在编译时就已经确定代理类和被代理类的关系,代理类是在编译阶段就确定的。静态代理的优点是简单易懂,缺点是需要手动编写代理类的代码,如果要代理的类很多,工作量将变得很大。

  • 动态代理是在程序运行时通过反射机制动态地创建代理类和实例。相比于静态代理,动态代理的优点是可以减少编码工作量,只需编写通用的代理类即可。同时,动态代理可以代理多个类,使得代码更加灵活。

静态代理和动态代理都是常见的设计模式,用于实现在不修改原始对象的情况下对其进行扩展或增强。下面我将为您提供静态代理和动态代理的代码示例。

  1. 静态代理示例:
// 定义一个接口
public interface Subject {
    void doSomething();
}

// 原始对象实现接口
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something.");
    }
}

// 静态代理类实现接口
public class ProxySubject implements Subject {
    private RealSubject realSubject;

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

    @Override
    public void doSomething() {
        System.out.println("ProxySubject do something before.");
        realSubject.doSomething();
        System.out.println("ProxySubject do something after.");
    }
}

// 客户端使用代理对象调用方法
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.doSomething();
    }
}
  1. 动态代理示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义一个接口
public interface Subject {
    void doSomething();
}

// 原始对象实现接口
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something.");
    }
}

// 动态代理类实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxy do something before.");
        Object result = method.invoke(target, args);
        System.out.println("DynamicProxy do something after.");
        return result;
    }
}

// 客户端使用动态代理对象调用方法
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        DynamicProxy dynamicProxy = new DynamicProxy(realSubject);

        // 创建动态代理对象
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                dynamicProxy);

        proxySubject.doSomething();
    }
}

CGLib和JDK Proxy代理的区别及代码示例

CGLib是一个强大的高性能的代码生成包,可以在运行时扩展Java类与实现Java接口。相比于JDK Proxy,CGLib不要求被代理类实现任何接口,但要求被代理方法不能为final或private。

代码示例:

  1. CGLib代理示例:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 原始对象类
public class RealObject {
    public void doSomething() {
        System.out.println("RealObject do something.");
    }
}

// CGLib代理类
public class CGLibProxy implements MethodInterceptor {
    private Object target;

    public Object createProxy(Object target) {
        this.target = target;

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);

        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CGLibProxy do something before.");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("CGLibProxy do something after.");

        return result;
    }
}

// 客户端使用CGLib代理对象调用方法
public class Client {
    public static void main(String[] args) {
        RealObject realObject = new RealObject();
        CGLibProxy cgLibProxy = new CGLibProxy();

        RealObject proxyObject = (RealObject) cgLibProxy.createProxy(realObject);
        proxyObject.doSomething();
    }
}

在上述示例中,我们定义了一个原始对象类(RealObject),其中有一个doSomething方法需要被代理。

CGLibProxy类实现了CGLib库的MethodInterceptor接口,并重写intercept方法。在intercept方法中,我们可以在调用原始对象的方法之前和之后进行前置和后置操作。createProxy方法用于创建CGLib代理对象。

在客户端,我们创建了原始对象realObject和CGLibProxy对象cgLibProxy。然后,通过调用cgLibProxy的createProxy方法,传入原始对象,即可获取到CGLib代理对象proxyObject。最后,通过proxyObject调用doSomething方法。

  1. JDK Proxy代理示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 原始对象接口
public interface Subject {
    void doSomething();
}

// 原始对象类
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something.");
    }
}

// JDK Proxy代理类
public class JDKProxy implements InvocationHandler {
    private Object target;

    public Object createProxy(Object target) {
        this.target = target;

        return Proxy.newProxyInstance(
                this.target.getClass().getClassLoader(),
                this.target.getClass().getInterfaces(),
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDKProxy do something before.");
        Object result = method.invoke(this.target, args);
        System.out.println("JDKProxy do something after.");

        return result;
    }
}

// 客户端使用JDK Proxy代理对象调用方法
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        JDKProxy jdkProxy = new JDKProxy();

        Subject proxySubject = (Subject) jdkProxy.createProxy(realSubject);
        proxySubject.doSomething();
    }
}

在以上示例中,我们同样有一个原始对象接口Subject和一个实现了该接口的原始对象类RealSubject。

JDKProxy类实现了Java标准库的InvocationHandler接口,并重写invoke方法。在invoke方法中,我们可以在调用原始对象的方法之前和之后进行前置和后置操作。createProxy方法用于创建JDK动态代理对象。

在客户端,我们创建了原始对象realSubject和JDKProxy对象jdkProxy。然后,通过调用jdkProxy的createProxy方法,传入原始对象,即可获取到JDK Proxy代理对象proxySubject。最后,通过proxySubject调用doSomething方法。

请注意,CGLib代理是基于继承的技术,生成的代理对象是目标类的子类。
而JDK Proxy代理是基于接口的技术,生成的代理对象实现了与目标类相同的接口。

总结

代理模式是一种常见的设计模式,通过创建一个代理类来控制对真实对象的访问。在实际开发中,我们可以根据具体需求选择静态代理或动态代理,也可以根据需求选择CGLib或JDK Proxy代理。通过合理运用代理模式,我们可以提高代码的灵活性和可维护性,从而更好地满足客户端的需求。

posted @   yue_stack  阅读(43)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示