面试系列 - Java代理模式详解

本文详细解释了代理模式,介绍了静态代理的实现方式,包括接口定义、目标类和代理类的设计,以及静态代理的优缺点。同时,展示了Java的JDK动态代理和CGLIB动态代理的使用示例,讨论了它们在代理实现中的应用和区别。
摘要由CSDN通过智能技术生成

代理模式是一种结构型设计模式,它允许你提供一个代理或替代品来控制对另一个对象的访问。代理对象通常充当客户端和实际目标对象之间的中介,可以用于各种用途,例如延迟加载、访问控制、监视、记录日志等。

一、代理模式包括以下几个关键角色

  1. 抽象主题(Subject): 定义了目标对象和代理对象的共同接口,客户端通过这个接口与目标对象交互。

  2. 具体主题(Real Subject): 实际的目标对象,代理对象所代表的真正业务逻辑。

  3. 代理(Proxy): 包含一个指向具体主题的引用,它实现了与抽象主题相同的接口,并可以在其方法中添加额外的逻辑。

二、静态代理

静态代理是代理模式的一种实现方式,它在编译期间就已经确定了代理关系。在静态代理中,代理类和目标类都必须在编码时已经存在,代理类通过实现与目标类相同的接口或继承与目标类相同的父类来实现代理。

静态代理的基本步骤和示例:

  1. 定义一个接口(或抽象类),用于声明目标对象和代理对象共同拥有的方法。

  2. 创建一个目标类,它实现了上述接口并提供了具体的业务逻辑。

  3. 创建一个代理类,它也实现了上述接口,并包含一个对目标对象的引用。代理类中的方法通常包含了一些额外的逻辑,例如日志记录、性能监测等。

  4. 在客户端代码中,创建目标对象和代理对象,然后通过代理对象调用方法。

下面是一个简单的 Java 示例,演示了静态代理的使用:

// 步骤1:定义接口
interface Subject {
    void doSomething();
}

// 步骤2:创建目标类
class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("RealSubject is doing something.");
    }
}

// 步骤3:创建代理类
class Proxy implements Subject {
    private RealSubject realSubject;

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

    public void doSomething() {
        // 可以在这里添加额外的逻辑,如日志记录、性能监测等
        System.out.println("Proxy is doing something.");
        realSubject.doSomething();
    }
}

// 步骤4:客户端代码
public class StaticProxyExample {
    public static void main(String[] args) {
        Subject proxy = new Proxy();
        proxy.doSomething();
    }
}

在上面的示例中,Subject 是接口,RealSubject 是目标类,Proxy 是代理类。代理类中的 doSomething 方法在调用目标对象的 doSomething 方法之前,添加了一些额外的逻辑。客户端代码通过代理对象调用方法。

静态代理的优点是简单,易于理解和实现。但它的缺点是每个代理类只能代理一个特定的目标类,如果需要代理多个不同的目标类,就需要创建多个代理类。此外,代理类的维护和扩展也可能会变得复杂。

总之,静态代理是一种简单而直观的代理模式实现方式,适用于特定的场景,但在某些情况下可能会引入大量的代理类。

三、Java 动态代理

java 动态代理是一种在运行时生成代理类的机制,用于代理其他类的方法调用。动态代理通常用于实现横切关注点(cross-cutting concerns)如日志、事务管理、性能监控等。Java 提供了两种主要的动态代理机制:基于接口的 JDK 动态代理和基于类的 CGLIB 动态代理。

1、JDK 动态代理

JDK 动态代理是 Java 标准库中的一部分,它要求被代理的类必须实现一个或多个接口。动态代理的核心类是 java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

下面是 JDK 动态代理的基本步骤:

  1. 创建一个实现 InvocationHandler 接口的代理处理器类,通常包含一个 invoke 方法,该方法在代理对象的方法被调用时执行所需的逻辑。

  2. 使用 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) 方法创建代理对象。这个方法接受一个类加载器、一组接口和代理处理器。

  3. 使用代理对象调用方法。当调用代理对象的方法时,invoke 方法将被调用,实际的逻辑由代理处理器定义。

示例代码:

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

interface MyInterface {
    void doSomething();
}

class MyRealObject implements MyInterface {
    public void doSomething() {
        System.out.println("Real object is doing something.");
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method invocation.");
        Object result = method.invoke(target, args);
        System.out.println("After method invocation.");
        return result;
    }
}

public class DynamicProxyExample {
    public static void main(String[] args) {
        MyInterface realObject = new MyRealObject();
        MyInvocationHandler handler = new MyInvocationHandler(realObject);
        
        MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(
            realObject.getClass().getClassLoader(),
            new Class<?>[] { MyInterface.class },
            handler
        );
        
        proxyObject.doSomething();
    }
}
2、CGLIB 动态代理

CGLIB(Code Generation Library)是一个强大的代码生成库,它可以在运行时动态生成类和方法。CGLIB 动态代理不要求被代理的类实现接口,它通过生成一个被代理类的子类来实现代理。

下面是 CGLIB 动态代理的基本步骤:

  1. 创建一个 CGLIB 代理对象,通常使用 Enhancer 类。

  2. 为代理对象设置目标类和方法拦截器(通常是一个方法拦截器类或回调函数)。

  3. 调用代理对象的方法,方法拦截器将在目标方法执行前后执行所需的逻辑。

示例代码:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

class MyRealClass {
    public void doSomething() {
        System.out.println("Real class is doing something.");
    }
}

class MyMethodInterceptor implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method invocation.");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method invocation.");
        return result;
    }
}

public class CglibProxyExample {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyRealClass.class);
        enhancer.setCallback(new MyMethodInterceptor());

        MyRealClass proxyObject = (MyRealClass) enhancer.create();
        
        proxyObject.doSomething();
    }
}

注意:CGLIB 动态代理通常需要引入 CGLIB 库,而 JDK 动态代理是 Java 标准库的一部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

境里婆娑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值