设计模式之房产中介——代理模式

发布于:2025-06-29 ⋅ 阅读:(17) ⋅ 点赞:(0)

手撕设计模式之房产中介——代理模式

1.业务需求

​ 大家好,我是菠菜啊,好久不见,今天给大家带来的是——代理模式。老规矩,在介绍这期内容前,我们先来看看这样的需求:我们有一套房产需要出售,但是我们抽不开身去带客户看房对接而且获客方式有限,我们该怎么实现?

在这里插入图片描述

2.代码实现

Talk is cheap,show me your code.

初版实现思路:

​ 既然自己没时间、没客源,可以找个中间人不就行了,这个中间人就是房产代理。

初版代码如下:

//房屋售卖接口
public interface HouseSaleService {
    void saleHouse();
}
//房东类
public class HouseOwner implements HouseSaleService {
    @Override
    public void saleHouse() {
        System.out.println("我是房东,我签订售房合同");
        System.out.println("我是房东,售出房源");

    }
}
//房产中介类
public class ProxyHouse implements HouseSaleService{
    private HouseSaleService houseSaleService;

    public ProxyHouse(HouseSaleService houseSaleService) {
        this.houseSaleService = houseSaleService;
    }
    @Override
    public void saleHouse() {
        System.out.println("房产中介——开始带客户看房");
        houseSaleService.saleHouse();
        System.out.println("房产中介——房源售出,结束");
    }
}
public class Client {
    public static void main(String[] args) {
        HouseSaleService houseSaleService = new HouseOwner();
        HouseSaleService proxyHouse = new ProxyHouse(houseSaleService);
        proxyHouse.saleHouse();
    }
}

输出结果:

在这里插入图片描述

实现代码结构图:

在这里插入图片描述

这个实现过程其实就是代理设计模式,属于代理模式中的静态代理。

3.需求升级

我们现在不是房东了,我们现在是一个中介平台,平台上有千千万万个房东和中介,如果还是实现上述代理买房的需求,交易的流程是一样的,该怎么做呢?不会添加那么多房产代理人吧。

//售房调用处理器类
public class HouseSaleInvocationHandler implements InvocationHandler {
    //房东
    private Object target;

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

    //三个参数:代理对象实例、方法对象(Method)和参数数组
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       System.out.println("动态生成房产中介代理——开始带客户看房");
        Object result =  method.invoke(target, args);
        System.out.println("动态生成房产中介代理——房源售出,结束");
        return result;
    }

    //创建动态代理对象
    public static Object newProxyInstance(Object target)
    {
        //传入目标对象的类加载器,目标对象实现的接口,调用处理器
       return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new HouseSaleInvocationHandler(target));
    }
}
//客户端(动态代理)
public class Client2 {
    public static void main(String[] args) {
        HouseSaleService houseSaleService = (HouseSaleService)HouseSaleInvocationHandler.newProxyInstance(new HouseOwner());
        houseSaleService.saleHouse();
    }
}

​ 执行结果:

在这里插入图片描述

​ 上述代码可以实现一套代理流程动态为多个房东生成房产代理,无需手动一个个手动创建。有没有同学觉得很熟悉,看过jdk源码的同学应该很熟悉(详细实现过程见下方源码剖析部分),它是利用java.lang.reflect包下的ProxyInvocationHandler核心类实现动态代理机制的,又称JDK的动态代理。实现原理:在运行代码时利用反射动态生成代理类,将目标方法的调用都转发到InvocationHandler的invoke方法,利用反射机制执行目标方法并插入增强逻辑。

核心流程如下:

在这里插入图片描述

思考:

​ 上述代码只能解决实现过售卖接口的房东需求,那些没通过实现售卖接口的个人房东好像满足不了他们的需求,所以又有另一种实现方式。

个人房东代码改造:

pom依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
//cglib代理类
public class CglibProxyHouse {
    
    //获取代理对象
    public static Object getInstance(Object target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());// 设置目标类
        enhancer.setCallback(new CglibMethodInterceptor());// 设置方法拦截器
        return enhancer.create();
    }

}
//cglib方法拦截增强类
public class CglibMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("动态生成房产中介代理———开始带客户看房-CglibProxyHouse");
        Object result=methodProxy.invokeSuper(proxy, args);// 调用父类(目标类)的方法
        System.out.println("动态生成房产中介代理———房源售出,结束-CglibProxyHouse");
        return result;
    }
}
//个人房东
public class OtherHouseOwner  {
    public  void saleHouse() {
        System.out.println("我是个人房东,我签订售房合同");
        System.out.println("我是个人房东,售出房源");

    }
}
//Cglib动态代理测试类
public class Client3 {
    public static void main(String[] args) {
        OtherHouseOwner houseOwner = (OtherHouseOwner)  CglibProxyHouse.getInstance(new OtherHouseOwner());
        houseOwner.saleHouse();
    }
}

运行结果:

在这里插入图片描述

​ 上述代码实现了个人房东动态代理卖房需求,个人房东无需实现响应接口。它利用net.sf.cglib.proxy包下的EnhancerMethodInterceptor核心类实现动态代理机制的,又称CGLIB动态代理CGLIB通过继承目标类并重写非final方法,在运行时使用ASM字节码技术动态生成代理子类,将方法调用委托给MethodInterceptor实现增强逻辑,并借助FastClass机制通过方法索引直接调用提升性能。

在这里插入图片描述

动态代理对比:

特性 JDK动态代理 CGLIB
代理方式 实现接口 继承目标类
性能 反射调用,较慢 FastClass调用,较快
依赖 无第三方库 需CGLIB库
目标类要求 必须实现接口 不能是final类/方法
初始化开销 大(生成两个FastClass)
方法调用模式 通过InvocationHandler 通过MethodInterceptor

4.定义

​ 代理设计模式是一种结构型设计模式,其核心思想是提供一个代理对象来控制对原始对象的访问。代理充当原始对象的中间层,允许在访问原始对象前后添加额外逻辑,而无需修改原始对象本身。

组成部分如下:

  1. 代理对象(Proxy)

    • 实现与原始对象相同的接口
    • 持有对原始对象的引用
    • 控制客户端对原始对象的访问
  2. 原始对象(Real Subject)

    • 实际执行业务逻辑的目标对象
  3. 抽象接口(Subject)

    • 定义代理和原始对象的共同接口,确保二者可互换使用

      在这里插入图片描述

5.应用场景

场景类型 典型用途 实例
虚拟代理 延迟创建开销大的对象 图片懒加载:代理先显示占位图,真正需要时才加载高清图片
远程代理 隐藏远程调用的复杂性 RPC框架:代理封装网络通信细节,客户端像调用本地对象一样调用远程服务
保护代理 控制访问权限 权限校验:代理验证用户权限后再允许访问敏感操作
缓存代理 缓存昂贵操作的结果 API请求缓存:代理缓存计算结果,重复请求直接返回结果,避免重复计算
日志代理 记录访问日志 审计系统:代理在方法调用前后记录日志和时间戳
智能引用代理 管理对象生命周期 自动释放资源:代理统计对象引用计数,引用归零时自动销毁对象

适用性总结

✅ 需要隔离客户端与复杂系统(如远程服务)
✅ 需要延迟初始化高开销对象
✅ 需添加访问控制或安全层
✅ 需透明添加日志、监控等横切关注点
✅ 需实现智能引用(如对象池、缓存)

典型场景:

​ Spring AOP 的底层机制完全基于代理模式实现,通过动态代理在运行时生成代理对象,将切面逻辑(如日志、事务等)织入目标方法中。其具体实现分为两种机制:JDK 动态代理CGLIB 代理,由 Spring 根据目标类的特性自动选择或通过配置强制指定。目标类实现了接口,使用JDK 动态代理;目标类未实现接口,CGLIB 代理,也可强制指定。

源码剖析

1.JDK动态代理

1.1 Proxy.newProxyInstance() 入口方法
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) {
    // 1. 验证接口和处理器有效性
    Objects.requireNonNull(h);
    final Class<?>[] intfs = interfaces.clone();
    
    // 2. 获取或生成代理类
    Class<?> cl = getProxyClass0(loader, intfs);
    
    try {
        // 3. 获取代理类构造器
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        
        // 4. 创建代理实例
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        // 异常处理...
    }
}
1.2 代理类生成机制(getProxyClass0)
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    // 1. 接口数量限制(最多65535个)
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
    
    // 2. 从缓存获取或生成代理类
    return proxyClassCache.get(loader, interfaces);
}

代理类缓存使用WeakCache实现,核心逻辑在ProxyClassFactory中:

private static final class ProxyClassFactory
    implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
    @Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
        // 1. 生成唯一代理类名
        long num = nextUniqueNumber.getAndIncrement();
        String proxyName = proxyPkg + proxyClassNamePrefix + num;
        
        // 2. 生成代理类字节码
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);
        
        // 3. 定义代理类
        return defineClass0(loader, proxyName,
                           proxyClassFile, 0, proxyClassFile.length);
    }
}
1.3 代理类字节码生成(ProxyGenerator)

generateProxyClass方法生成代理类的字节码,其核心逻辑如下:

public static byte[] generateProxyClass(final String name,
                                        Class<?>[] interfaces,
                                        int accessFlags) {
    ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
    // 真正生成字节码
    final byte[] classFile = gen.generateClassFile();
    
    // 可选项:保存生成的字节码到文件(调试用)
    if (saveGeneratedFiles) {
        java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        FileOutputStream file = 
                            new FileOutputStream(dotToSlash(name) + ".class");
                        file.write(classFile);
                        file.close();
                    } catch (IOException e) { /* 忽略 */ }
                    return null;
                }
            });
    }
    return classFile;
}
1.4 生成的代理类结构(反编译示例)

假设我们代理HouseSaleService接口,生成的$Proxy0.class反编译后:

public final class $Proxy0 extends Proxy implements HouseSaleService {
    private static Method m1;  // hashCode()
    private static Method m2;  // equals()
    private static Method m3;  // toString()
    private static Method m4;  // saleHouse()
    
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("hashCode");
            m2 = Class.forName("java.lang.Object").getMethod("equals", 
                Class.forName("java.lang.Object"));
            m3 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.example.HouseSaleService").getMethod("saleHouse");

        } catch (NoSuchMethodException e) { /* 处理异常 */ }
    }
    
    public $Proxy0(InvocationHandler h) {
        super(h);  // 调用Proxy的构造函数
    }
    
    public final void saleHouse() {
        try {
            // 关键:调用InvocationHandler的invoke方法
            super.h.invoke(this, m4, null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    
    // 其他Object方法实现类似...
}

代理对象实现目标接口,方法调用里其实还是调用InvocationHandler的invoke方法。

2.CGLIB动态代理

2.1Enhancer 入口类

创建代理对象通常使用以下代码:

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class); // 设置目标类
enhancer.setCallback(new MyMethodInterceptor()); // 设置回调(拦截器)
TargetClass proxy = (TargetClass) enhancer.create(); // 生成代理对象
2.2 enhancer.create() 方法调用链
// Enhancer.java
public Object create() {
    // 关键:不使用参数
    return createHelper();
}

private Object createHelper() {
    // 1. 验证回调类型
    preValidate();
    // 2. 生成代理类
    Class<?> proxyClass = createClass();
    // 3. 创建代理实例
    return createUsingReflection(proxyClass);
}
2.3 代理类生成(createClass)
// AbstractClassGenerator.java
protected Class<?> createClass() {
    // 使用字节码生成器生成字节码
    byte[] b = strategy.generate(this);
    // 定义类
    return ReflectUtils.defineClass(getClassName(), b, loader);
}
2.4 字节码生成核心:Enhancer.generateClass

CGLIB通过ASM库直接操作字节码,关键逻辑在Enhancer.generateClass方法中:

// Enhancer.java
public void generateClass(ClassVisitor v) {
    // 1. 创建类结构
    ClassEmitter ce = new ClassEmitter(v);
    ce.begin_class(/* 版本号 */, 
                   ACC_PUBLIC, 
                   getClassName(), 
                   getSuperclass(), 
                   getInterfaces(), 
                   "<generated>");
    
    // 2. 添加字段
    ce.declare_field(ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
    ce.declare_field(ACC_PRIVATE, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
    ce.declare_field(ACC_PRIVATE, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
    
    // 3. 生成构造函数
    generateConstructor(ce);
    
    // 4. 生成回调设置方法
    generateSetCallbacks(ce);
    generateSetCallback(ce);
    generateGetCallback(ce);
    
    // 5. 重写目标方法
    for (Method method : getMethods()) {
        generateMethod(ce, method);
    }
    
    ce.end_class();
}
2.5 方法生成逻辑(generateMethod)
// Enhancer.java
private void generateMethod(ClassEmitter ce, Method method) {
    // 1. 创建方法签名
    Signature sig = ReflectUtils.getSignature(method);
    
    // 2. 创建方法体
    CodeEmitter e = ce.begin_method(ACC_PUBLIC, sig, null);
    
    // 3. 获取回调
    e.load_this();
    e.getfield(CALLBACK_FIELD);
    
    // 4. 检查回调是否存在
    Label noCallback = e.make_label();
    e.dup();
    e.ifnull(noCallback);
    
    // 5. 准备调用参数
    e.push(method);
    e.create_arg_array();
    e.push(methodProxy);
    
    // 6. 调用拦截器
    e.invoke_interface(METHOD_INTERCEPTOR_TYPE, 
                       new Signature("intercept", 
                                     Type.OBJECT, 
                                     new Type[]{TYPE_OBJECT, 
                                                TYPE_METHOD, 
                                                TYPE_OBJECT_ARRAY, 
                                                TYPE_METHOD_PROXY}));
    
    // 7. 结果处理
    e.unbox_or_zero(e.getReturnType());
    e.return_value();
    
    // 8. 没有回调时的处理
    e.mark(noCallback);
    e.pop();
    // 调用原始方法
    super.generateMethod(ce, method);
    e.return_value();
    
    e.end_method();
}
2.6 生成的代理类结构(反编译示例)

使用CGLIB代理后生成的代理类大致如下:

public class OtherHouseOwner$$EnhancerByCGLIB$$12345678 extends OtherHouseOwner implements Factory {
    private MethodInterceptor interceptor;
    private static final Method CGLIB$saleHouse$0$Method;
    private static final MethodProxy CGLIB$saleHouse$0$Proxy;

    static {
        // 初始化目标方法和代理方法
        CGLIB$saleHouse$0$Method = ReflectUtils.findMethods(new String[]{"saleHouse", "()V"}).get(0);
        CGLIB$saleHouse$0$Proxy = MethodProxy.create(OtherHouseOwner.class, OtherHouseOwner$$EnhancerByCGLIB$$12345678.class, "()V", "saleHouse", "CGLIB$saleHouse$0");
    }

    // 重写目标方法
    public final void saleHouse() {
        MethodInterceptor tmp = this.interceptor;
        if (tmp == null) {
            super.saleHouse(); // 如果未设置拦截器,直接调用父类方法
        } else {
            // 调用拦截器的intercept方法
            tmp.intercept(this, CGLIB$saleHouse$0$Method, new Object[0], CGLIB$saleHouse$0$Proxy);
        }
    }

    // 原始方法的直接调用(避免拦截)
    final void CGLIB$saleHouse$0() {
        super.saleHouse();
    }

    // 其他方法...
}

如果未设置拦截器,直接调用父类方法;如果有设置方法拦截器,直接回调拦截器方法。

2.7 MethodProxy 工作原理

MethodProxy是CGLIB高效调用的关键,它通过生成两个FastClass(目标类FastClass和代理类FastClass)实现快速方法调用。

// MethodProxy.java
public Object invoke(Object obj, Object[] args) throws Throwable {
    try {
        // 使用目标类的FastClass直接调用原始方法
        return fastClass.invoke(targetIndex, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        // 使用代理类的FastClass调用代理类中的原始方法(即CGLIB$xxx方法)
        return fastClass.invoke(superIndex, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}
2.8 FastClass 机制

FastClass为每个方法分配一个索引(index),通过索引直接调用方法,避免反射开销。

// 生成的TargetFastClass
public Object invoke(int index, Object obj, Object[] args) {
    OtherHouseOwner otherHouseOwner = (OtherHouseOwner) obj;
    switch (index) {
        case 0:
            otherHouseOwner.saleHouse();
            return null;
        // 其他方法...
    }
}

// 生成的ProxyFastClass
public Object invoke(int index, Object obj, Object[] args) {
    OtherHouseOwner$$EnhancerByCGLIB proxy = (OtherHouseOwner$$EnhancerByCGLIB) obj;
    switch (index) {
        case 0:
            proxy.CGLIB$saleHouse$0();
            return null;
        // 其他方法...
    }
}

法,避免反射开销。

// 生成的TargetFastClass
public Object invoke(int index, Object obj, Object[] args) {
    OtherHouseOwner otherHouseOwner = (OtherHouseOwner) obj;
    switch (index) {
        case 0:
            otherHouseOwner.saleHouse();
            return null;
        // 其他方法...
    }
}

// 生成的ProxyFastClass
public Object invoke(int index, Object obj, Object[] args) {
    OtherHouseOwner$$EnhancerByCGLIB proxy = (OtherHouseOwner$$EnhancerByCGLIB) obj;
    switch (index) {
        case 0:
            proxy.CGLIB$saleHouse$0();
            return null;
        // 其他方法...
    }
}

技术需要沉淀,同样生活也是~
个人链接:博客,欢迎一起交流