Java代理模式全面解析

一、代理模式基础概念

1.1 什么是代理模式

代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不修改目标对象代码的情况下增强其功能。

1.2 代理模式的核心组成

  • ​抽象主题(Subject)​​: 定义代理和真实主题的公共接口

  • ​真实主题(RealSubject)​​: 实际业务逻辑的实现类

  • ​代理类(Proxy)​​: 持有真实主题的引用,提供与真实主题相同的接口

1.3 代理模式的应用场景

  • 远程代理(Remote Proxy):为远程对象提供本地代理

  • 虚拟代理(Virtual Proxy):延迟创建开销大的对象

  • 保护代理(Protection Proxy):控制对原始对象的访问权限

  • 智能引用(Smart Reference):在访问对象时执行额外操作

二、静态代理详解

2.1 静态代理实现原理

静态代理在编译期就已经确定代理关系,代理类和目标类实现相同的接口,代理类通过组合方式持有目标对象引用。

2.2 完整静态代理案例

接口定义
public interface BuyClothes {
    void clothes(String size);
}
目标类实现
public class ClothesFactory implements BuyClothes {
    public void clothes(String size) {
        System.out.println("为您定制了一款大小为" + size + "的衣服");
    }
}
代理类实现
public class ClothesProxy implements BuyClothes {
    private ClothesFactory clothesFactory;
    
    public ClothesProxy() {
        this.clothesFactory = new ClothesFactory();
    }
    
    @Override
    public void clothes(String size) {
        preService();
        clothesFactory.clothes(size);
        postService();
    }
    
    private void preService() {
        System.out.println("[静态代理]为您进行市场调研");
    }
    
    private void postService() {
        System.out.println("[静态代理]为您提供售后服务");
    }
}
客户端调用
public class StaticProxyTest {
    public static void main(String[] args) {
        BuyClothes proxy = new ClothesProxy();
        proxy.clothes("XL");
    }
}

2.3 静态代理的优缺点

​优点​​:

  • 结构清晰,易于理解

  • 不改变目标对象的情况下扩展功能

​缺点​​:

  • 代理类和目标类必须实现相同接口

  • 每个目标类都需要一个代理类,导致类数量膨胀

  • 接口变更时,代理类和目标类都需要修改

三、动态代理深入解析

3.1 JDK动态代理原理

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

  • java.lang.reflect.Proxy: 创建代理实例

  • java.lang.reflect.InvocationHandler: 调用处理器接口

3.2 完整JDK动态代理案例

新增鞋子接口
public interface BuyShoes {
    void shoes(String size);
}
鞋子目标类
public class ShoesFactory implements BuyShoes {
    @Override
    public void shoes(String size) {
        System.out.println("为您定制了一款大小为" + size + "的鞋子");
    }
}
动态代理处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxyHandler implements InvocationHandler {
    private Object target;
    
    public DynamicProxyHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        preProcess();
        Object result = method.invoke(target, args);
        postProcess();
        return result;
    }
    
    private void preProcess() {
        System.out.println("[动态代理]执行前置处理");
    }
    
    private void postProcess() {
        System.out.println("[动态代理]执行后置处理");
    }
}
客户端调用
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
    public static void main(String[] args) {
        // 代理衣服购买
        BuyClothes clothes = new ClothesFactory();
        DynamicProxyHandler clothesHandler = new DynamicProxyHandler(clothes);
        BuyClothes clothesProxy = (BuyClothes) Proxy.newProxyInstance(
            clothes.getClass().getClassLoader(),
            clothes.getClass().getInterfaces(),
            clothesHandler);
        clothesProxy.clothes("L");
        
        // 代理鞋子购买
        BuyShoes shoes = new ShoesFactory();
        DynamicProxyHandler shoesHandler = new DynamicProxyHandler(shoes);
        BuyShoes shoesProxy = (BuyShoes) Proxy.newProxyInstance(
            shoes.getClass().getClassLoader(),
            shoes.getClass().getInterfaces(),
            shoesHandler);
        shoesProxy.shoes("42");
    }
}

3.3 JDK动态代理的优缺点

​优点​​:

  • 一个代理类可以代理多个接口

  • 减少代码冗余,提高可维护性

  • 符合开闭原则,系统扩展性好

​限制​​:

  • 只能代理接口,不能代理类

  • 反射调用有一定性能开销

四、CGLIB动态代理

4.1 CGLIB原理

CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它通过继承目标类并在运行时生成子类来实现代理。

4.2 CGLIB代理案例

目标类(不需要实现接口)
public class ProductService {
    public void createProduct(String name) {
        System.out.println("创建产品:" + name);
    }
}
CGLIB代理工厂
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxyFactory implements MethodInterceptor {
    public Object getProxy(Class<?> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, 
                          MethodProxy proxy) throws Throwable {
        preProcess();
        Object result = proxy.invokeSuper(obj, args);
        postProcess();
        return result;
    }
    
    private void preProcess() {
        System.out.println("[CGLIB代理]执行前置处理");
    }
    
    private void postProcess() {
        System.out.println("[CGLIB代理]执行后置处理");
    }
}
客户端调用
public class CglibTest {
    public static void main(String[] args) {
        CglibProxyFactory factory = new CglibProxyFactory();
        ProductService proxy = (ProductService) factory.getProxy(ProductService.class);
        proxy.createProduct("智能手机");
    }
}

4.3 CGLIB特点

​优势​​:

  • 可以代理普通类,不要求实现接口

  • 生成的代理类是目标类的子类

  • 方法调用比JDK动态代理更快

​限制​​:

  • 不能代理final类或final方法

  • 需要引入额外依赖

五、三种代理方式对比

特性

静态代理

JDK动态代理

CGLIB代理

实现方式

手动编码

反射机制

字节码生成

代理目标

接口

接口

编译期生成

性能

依赖

JDK自带

需要引入CGLIB

适用场景

简单固定代理

多接口代理

无接口类代理

六、Spring中的代理选择

Spring框架自动根据目标对象选择代理方式:

  1. 如果目标对象实现了接口 → 使用JDK动态代理

  2. 如果目标对象没有实现接口 → 使用CGLIB代理

  3. 可以通过配置强制使用CGLIB代理

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB
public class AppConfig {
    // 配置类
}

七、最佳实践建议

  1. ​优先使用JDK动态代理​​:符合面向接口编程原则

  2. ​必要时使用CGLIB​​:当需要代理类而非接口时

  3. ​避免滥用代理​​:明确代理的目的,不要为了使用模式而使用

  4. ​性能考虑​​:在高性能场景下评估代理开销

  5. ​结合AOP使用​​:Spring AOP等框架已经提供了良好的代理实现

通过本文的详细讲解和完整代码示例,您应该已经掌握了Java中各种代理模式的实现原理和使用场景。在实际开发中,可以根据具体需求选择合适的代理方式,灵活运用代理模式来增强系统功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值