Java基础教程(216)结构型模式之代理:设计模式幕后英雄:Java代理模式深度解密

代理模式核心概念

代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,在不改变原始类代码的情况下增加额外的功能。

代理模式主要分为三种角色:

  • Subject:定义真实对象和代理对象的共同接口
  • RealSubject:真实处理业务的目标对象
  • Proxy:包含对真实对象的引用,可以控制和增强真实对象的行为

静态代理:编译时确定

静态代理需要手动创建代理类,在编译时就已经确定代理关系。

// 共同接口
interface Image {
    void display();
}

// 真实对象
class RealImage implements Image {
    private String filename;
    
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    
    private void loadFromDisk() {
        System.out.println("Loading " + filename);
    }
    
    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }
}

// 代理类
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;
    
    public ProxyImage(String filename) {
        this.filename = filename;
    }
    
    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        // 前置处理
        System.out.println("Proxy: Before display");
        
        realImage.display();
        
        // 后置处理
        System.out.println("Proxy: After display");
    }
}

// 使用示例
public class StaticProxyDemo {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        image.display(); // 真实对象此时才创建
    }
}

静态代理的缺点是需要为每个目标类创建代理类,当接口增加方法时,目标和代理都需要修改。

JDK动态代理:运行时动态生成

JDK动态代理利用Java反射机制,在运行时动态生成代理类。

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

// 调用处理器
class LoggingHandler implements InvocationHandler {
    private Object target;
    
    public LoggingHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置处理
        System.out.println("调用方法: " + method.getName());
        
        // 调用真实对象的方法
        Object result = method.invoke(target, args);
        
        // 后置处理
        System.out.println("方法调用完成: " + method.getName());
        return result;
    }
}

// 使用示例
public class JdkDynamicProxyDemo {
    public static void main(String[] args) {
        // 创建真实对象
        Image realImage = new RealImage("test.jpg");
        
        // 创建代理对象
        Image proxyImage = (Image) Proxy.newProxyInstance(
            Image.class.getClassLoader(),
            new Class[]{Image.class},
            new LoggingHandler(realImage)
        );
        
        proxyImage.display();
    }
}

JDK动态代理要求目标类必须实现接口,代理对象是在运行时根据接口动态生成的。

CGLib动态代理:无需接口的方案

CGLib通过字节码技术生成目标类的子类来实现代理,不需要目标类实现接口。

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

class CglibProxyFactory implements MethodInterceptor {
    private Object target;
    
    public CglibProxyFactory(Object target) {
        this.target = target;
    }
    
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(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("CGLib代理: 开始执行 " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("CGLib代理: 执行完成 " + method.getName());
        return result;
    }
}

// 使用示例
public class CglibProxyDemo {
    public static void main(String[] args) {
        RealImage target = new RealImage("test.jpg");
        RealImage proxy = (RealImage) new CglibProxyFactory(target).getProxyInstance();
        proxy.display();
    }
}

CGLib创建的代理对象性能通常比JDK动态代理更高,但不能代理final类和final方法。

三种代理方式对比

特性

静态代理

JDK动态代理

CGLib动态代理

编译时要求

需要显式创建代理类

需要接口

不需要接口

性能

一般

较差(反射开销)

较高(字节码增强)

灵活性

依赖

无特殊依赖

Java标准库

需要CGLib库

实际应用场景

代理模式在现实项目中有广泛应用:

  1. Spring AOP:基于动态代理实现面向切面编程
  2. Hibernate延迟加载:使用代理实现数据的懒加载
  3. RPC框架:客户端使用代理透明调用远程服务
  4. 安全代理:控制对敏感对象的访问权限
  5. 日志记录:在方法调用前后添加日志功能

总结

代理模式是Java设计中极为重要的结构型模式,它通过引入代理对象实现对真实对象的间接访问,从而可以在不修改原有代码的情况下增强功能。根据具体需求,可以选择静态代理、JDK动态代理或CGLib动态代理,每种方式都有其适用场景和优缺点。

掌握代理模式不仅有助于写出更加灵活和可维护的代码,也是理解Spring等主流框架实现原理的基础。在实际开发中,应根据项目需求选择最合适的代理方式,平衡灵活性、性能和复杂度。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

值引力

持续创作,多谢支持!

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

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

打赏作者

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

抵扣说明:

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

余额充值