「全网最细 + 实战源码案例」设计模式——代理模式

简介: 代理模式(Proxy Pattern)是一种结构型设计模式,通过代理对象控制对目标对象的访问并添加额外功能。它分为静态代理和动态代理,后者包括JDK动态代理和CGLIB动态代理。JDK动态代理基于接口反射生成代理类,而CGLIB通过继承目标类生成子类。代理模式适用于延迟初始化、访问控制、远程服务、日志记录和缓存等场景,优点是职责分离、符合开闭原则和提高安全性,缺点是增加系统复杂性。


核心思想
代理模式(Proxy Pattern)是一种结构型设计模式,用于为对象提供一个代理对象,从而控制对目标对象的访问。代理模式可以为目标对象添加额外的功能,同时不改变目标对象的代码。

结构

  1. 抽象主题(Subject)
    定义代理对象和目标对象的通用接口,使代理对象可以替代目标对象。
  2. 真实主题(Real Subject)
    实现实际业务逻辑的对象,客户端最终想要访问的目标。
  3. 代理(Proxy)
    控制对真实主题的访问,负责与真实主题交互,可以添加额外功能。
    代理模式分类
    静态代理

动态代理
JDK 动态代理
代码实现:

package com.colin.patterns.structural_patterns.proxy.jdk_proxy;

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

public class ProxyFactory {

private Object target;

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

public Object getProxyObject(){
    return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("代售点收取一定费用");
                    return method.invoke(target, args);

                }
            }
    );
}
AI 代码解读

}
原理:
动态代理的核心是 动态生成代理类并加载到内存。它的执行流程如下:

代理对象创建
调用 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 方法:
loader: 指定类加载器,用于加载动态生成的代理类。
interfaces: 指定代理类需要实现的接口。
h: 代理对象的调用处理器,实现 InvocationHandler 接口。
生成代理类的字节码
JDK动态代理会在运行时动态生成代理类(字节码),这些代理类继承自 Proxy,并实现了目标对象的所有接口。
代理类加载
动态生成的代理类通过指定的类加载器加载到 JVM 中。
方法调用处理
当调用代理对象的方法时,实际会触发 InvocationHandler.invoke() 方法:
将目标方法的信息(包括方法对象和参数)传递到 invoke()。
在 invoke() 方法中,开发者可以自定义逻辑(如权限校验、日志记录等)。
如果需要调用目标对象的方法,则通过反射执行。
CGLIB 动态代理
实现过程:

package com.colin.patterns.structural_patterns.proxy.cglib_proxy;

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

import java.lang.reflect.Method;

public class ProxyFactory implements MethodInterceptor {

private Object target;

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

public Object getProxyInstance(){
    // 1.创建Enhancer对象
    Enhancer enhancer = new Enhancer();
    // 2.设置父类
    enhancer.setSuperclass(target.getClass());
    // 3.设置回调函数
    enhancer.setCallback(this);
    // 4.创建代理对象并返回
    return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

    System.out.println("代理点收取代理费");
    // 调用目标对象的方法
    Object obj = methodProxy.invokeSuper(o, objects);
    return obj;
}
AI 代码解读

}
原理:
基于继承生成代理类
CGLIB 会通过继承目标类,生成一个目标类的子类作为代理类。
子类会重写目标类的所有非 final 方法(final 方法无法被继承,不能被代理)。
方法的调用会被代理类拦截,通过 MethodInterceptor 实现代理逻辑。
字节码生成
CGLIB 使用 ASM框架 操作字节码,动态生成代理类的 .class 文件,并加载到 JVM 中。
Enhancer 是 CGLIB 的核心类,用于生成代理类。
代理类会在运行时动态加载到内存中,而非提前编译。
方法拦截
代理类的方法调用会被拦截,并由 MethodInterceptor 接口的 intercept 方法处理。
在 intercept 方法中可以添加增强逻辑,决定是否调用目标类的方法(通过 MethodProxy)。
方法调用
如果需要调用目标类的方法,MethodProxy.invokeSuper 会直接调用父类方法,避免使用反射调用,性能较高。
JDK动态代理与CGLIB的区别
特性

JDK动态代理

CGLIB动态代理

是否需要接口

必须实现接口

不需要接口,直接代理类

实现方式

基于反射生成代理类

基于字节码操作生成子类

性能

较低,依赖反射(1.8 之后更快)

较高,直接调用字节码

使用场景

目标类有接口

目标类无接口或对性能要求较高

限制

目标类必须实现接口

目标类不能是 final

适用场景
延迟初始化 (虚拟代理)。 如果你有一个偶尔使用的重量级服务对象, 一直保持该对象运行会消耗系统资源时, 可使用代理模式。
你无需在程序启动时就创建该对象, 可将对象的初始化延迟到真正有需要的时候。
访问控制 (保护代理)。 如果你只希望特定客户端使用服务对象, 这里的对象可以是操作系统中非常重要的部分, 而客户端则是各种已启动的程序 (包括恶意程序), 此时可使用代理模式。
代理可仅在客户端凭据满足要求时将请求传递给服务对象。
本地执行远程服务 (远程代理)。 适用于服务对象位于远程服务器上的情形。
在这种情形中, 代理通过网络传递客户端请求, 负责处理所有与网络相关的复杂细节。
记录日志请求 (日志记录代理)。 适用于当你需要保存对于服务对象的请求历史记录时。
代理可以在向服务传递请求前进行记录。
缓存请求结果 (缓存代理)。 适用于需要缓存客户请求结果并对缓存生命周期进行管理时, 特别是当返回结果的体积非常大时。
代理可对重复请求所需的相同结果进行缓存, 还可使用请求参数作为索引缓存的键值。
智能引用。 可在没有客户端使用某个重量级对象时立即销毁该对象。
代理会将所有获取了指向服务对象或其结果的客户端记录在案。 代理会时不时地遍历各个客户端, 检查它们是否仍在运行。 如果相应的客户端列表为空, 代理就会销毁该服务对象, 释放底层系统资源。
代理还可以记录客户端是否修改了服务对象。 其他客户端还可以复用未修改的对象。
优缺点
优点:
职责分离:代理类负责扩展功能,真实类专注于核心业务逻辑。
开闭原则:可以在不修改真实对象的情况下增强功能。
提高系统安全性:通过代理控制对真实对象的访问。
缺点:
增加系统复杂性
与其他模式的关系
适配器模式能为被封装对象提供不同的接口, 代理模式能为对象提供相同的接口, 装饰模式则能为对象提供加强的接口。
外观模式与代理的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。 代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换, 在这一点上它与外观不同。
装饰和代理有着相似的结构, 但是其意图却非常不同。 这两个模式的构建都基于组合原则, 也就是说一个对象应该将部分工作委派给另一个对象。 两者之间的不同之处在于代理通常自行管理其服务对象的生命周期, 而装饰的生成则总是由客户端进行控制。

目录
打赏
0
20
25
4
167
分享
相关文章
「全网最细 + 实战源码案例」设计模式——命令模式
命令模式(Command Pattern)是一种行为型设计模式,将请求封装成独立对象,从而解耦请求方与接收方。其核心结构包括:Command(命令接口)、ConcreteCommand(具体命令)、Receiver(接收者)和Invoker(调用者)。通过这种方式,命令的执行、撤销、排队等操作更易扩展和灵活。 适用场景: 1. 参数化对象以操作。 2. 操作放入队列或远程执行。 3. 实现回滚功能。 4. 解耦调用者与接收者。 优点: - 遵循单一职责和开闭原则。 - 支持命令组合和延迟执行。 - 可实现撤销、恢复功能。 缺点: - 增加复杂性和类数量。
42 14
「全网最细 + 实战源码案例」设计模式——命令模式
「全网最细 + 实战源码案例」设计模式——责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许将请求沿着处理者链进行发送。每个处理者可以处理请求或将其传递给下一个处理者,从而实现解耦和灵活性。其结构包括抽象处理者(Handler)、具体处理者(ConcreteHandler)和客户端(Client)。适用于不同方式处理不同种类请求、按顺序执行多个处理者、以及运行时改变处理者及其顺序的场景。典型应用包括日志处理、Java Web过滤器、权限认证等。
45 13
「全网最细 + 实战源码案例」设计模式——责任链模式
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
46 8
「全网最细 + 实战源码案例」设计模式——策略模式
「全网最细 + 实战源码案例」设计模式——模板方法模式
模板方法模式是一种行为型设计模式,定义了算法的骨架并在父类中实现不变部分,将可变部分延迟到子类实现。通过这种方式,它避免了代码重复,提高了复用性和扩展性。具体步骤由抽象类定义,子类实现特定逻辑。适用于框架设计、工作流和相似算法结构的场景。优点包括代码复用和符合开闭原则,缺点是可能违反里氏替换原则且灵活性较低。
55 7
「全网最细 + 实战源码案例」设计模式——模板方法模式
「全网最细 + 实战源码案例」设计模式——组合模式
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。它允许客户端以一致的方式对待单个对象和对象集合,简化了复杂结构的处理。组合模式包含三个主要组件:抽象组件(Component)、叶子节点(Leaf)和组合节点(Composite)。通过这种模式,客户端可以统一处理简单元素和复杂元素,而无需关心其内部结构。适用于需要实现树状对象结构或希望以相同方式处理简单和复杂元素的场景。优点包括支持树形结构、透明性和遵循开闭原则;缺点是可能引入不必要的复杂性和过度抽象。
66 22
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
134 11
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
21天前
|
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
83 40
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
52 19

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等