首页 > 其他分享 >代理模式

代理模式

时间:2024-10-17 13:34:16浏览次数:1  
标签:void Object request 代理 模式 proxy public

静态代理

静态代理是一种设计模式,用于在不改变目标对象的情况下,增加对目标对象的控制或功能。它的基本思想是创建一个代理类,该类实现与目标类相同的接口,并在其方法中调用目标对象的方法

优点:

  • 增强功能:可以在不改变目标类的情况下,增强其功能。
  • 代码复用:通过代理类可以重用目标类的代码。

缺点:

  • 代码膨胀:每增加一个目标类,就需要增加一个对应的代理类,导致代码量增大。
  • 灵活性差:代理类在编译时就被确定,不能动态改变。

示例:

// 定义接口
interface Subject {
    void request();
}

// 目标类
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 代理类
class ProxySubject implements Subject {
    private RealSubject realSubject;

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

    @Override
    public void request() {
        // 增强功能:在请求前后添加日志
        System.out.println("ProxySubject: Logging before request.");
        realSubject.request();
        System.out.println("ProxySubject: Logging after request.");
    }
}

// 测试
public class StaticProxyDemo {
    public static void main(String[] args) {
        // 创建代理类,ProxySubject 代理的是 Subject 类,如果不是 Subject 就不能代理,就要重新创建一个代理类
        Subject proxy = new ProxySubject();
        // 调用代理类的方法,内部还是会调用目标类的方法,但是代理方法增强过
        proxy.request();
    }
}

JDK 动态代理

静态代理最大的弊端就是每增加一种目标类就要增加一种代理类,所以静态代理除了特定的场景几乎不适用

使用 java.lang.reflect.Proxy#newProxyInstance 来创建代理类,这个方法一共三个参数:

  1. 目标类的类加载器

  2. 目标类实现的接口

  3. 执行处理器,是一个接口 InvocationHandler,里面只有一个方法(函数式接口)

    // 创建目标对象
    User user = new User();
    
    // 代理类
    User userProxy = (User) Proxy.newProxyInstance(
            user.getClass().getClassLoader(), // 目标类类加载器
            user.getClass().getInterfaces(),  // 目标类接口
            new InvocationHandler() { // 执行处理器,可以使用 lambda 表达式
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 可以在方法执行前后增强、args 是参数可以动态修改 等
    
                    // 执行目标方法
                    Object result = method.invoke(user, args);
                    // 返回目标方法执行结果
                    return result;
                }
            }
    );
    
    // 使用代理类调用方法
    userProxy.getName();
    

再一个示例

定义多个接口:

public interface SubjectA {
    void requestA();
}

public interface SubjectB {
    void requestB();
}

接口实现类:

public class RealSubjectA implements SubjectA {
    @Override
    public void requestA() {
        System.out.println("RealSubjectA: Handling request A.");
    }
}

public class RealSubjectB implements SubjectB {
    @Override
    public void requestB() {
        System.out.println("RealSubjectB: Handling request B.");
    }
}

执行处理器:

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

public class DynamicInvocationHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Proxy: Logging before request.");
        Object result = method.invoke(target, args);
        System.out.println("Proxy: Logging after request.");
        return result;
    }
}

使用:

import java.lang.reflect.Proxy;

public class DynamicProxyDemo {
    public static void main(String[] args) {
        // 代理 RealSubjectA
        RealSubjectA realSubjectA = new RealSubjectA();
        SubjectA proxyA = (SubjectA) Proxy.newProxyInstance(
                realSubjectA.getClass().getClassLoader(),
                realSubjectA.getClass().getInterfaces(),
                new DynamicInvocationHandler(realSubjectA) // 执行处理器使用都是同一个 DynamicInvocationHandler
        );
        proxyA.requestA();

        // 代理 RealSubjectB
        RealSubjectB realSubjectB = new RealSubjectB();
        SubjectB proxyB = (SubjectB) Proxy.newProxyInstance(
                realSubjectB.getClass().getClassLoader(),
                realSubjectB.getClass().getInterfaces(),
                new DynamicInvocationHandler(realSubjectB) // // 执行处理器使用都是同一个 DynamicInvocationHandler
        );
        proxyB.requestB();
    }
}

CGLIB 动态代理

JDK 动态代理要求目标类必须实现接口,如果目标类没有实现接口就要使用 CGLIB 动态代理,是三方实现的,所以要引入依赖

依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

目标类:

public class UserService {
    public void addUser(String user) {
        System.out.println("Adding user: " + user);
    }
}

创建 CGLIB 代理类:

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

public class UserServiceProxy implements MethodInterceptor {

    // 创建代理对象的方法
    public Object createProxy(Class<?> targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass); // 设置要代理的类
        enhancer.setCallback(this); // 设置回调
        return enhancer.create(); // 创建代理对象
    }

    @Override
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = proxy.invokeSuper(obj, args); // 调用目标类的方法
        System.out.println("After method: " + method.getName());
        return result;
    }
}

使用:

public class CGLIBProxyDemo {
    public static void main(String[] args) {
        // 创建 CGLIB 代理
        UserServiceProxy proxy = new UserServiceProxy();
        UserService userServiceProxy = (UserService) proxy.createProxy(UserService.class);

        // 使用代理对象调用方法
        userServiceProxy.addUser("John Doe");
    }
}

标签:void,Object,request,代理,模式,proxy,public
From: https://www.cnblogs.com/cyrushuang/p/18471934

相关文章

  • EDITPLUS-EditPlus设置护眼模式
    EditPlus版本号:EditPlus4.3(build1256)64-bitTools——>Preferences Colors——>Text取消Default勾选项 Background——>More选项配置如下参数后点击应用并保存 ......
  • 为什么要用工厂模式
    1.复合开闭原则,对扩展开放,对修改关闭。客户端比如feign调用时,当服务端修改代码后,客户端不需要修改代码。Java中的工厂方法模式(FactoryMethodPattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式。以下是对Java工厂方法模式的详细解析:一、定义与特点工厂方法模式定义......
  • 全域本地服务商抽佣系统解决跨区域代理运营商抽佣问题?
    全域本地服务商抽佣系统是为了解决跨区域抽佣问题而设计的,它允许商户在多个平台和地区进行销售,并通过一个统一的系统进行佣金的抽取和管理。这种系统通常具备以下特点:跨平台整合:能够与多个线上平台如抖音团购、快手等进行无缝对接,实现资源的有效整合和共享。实时抽佣:确保商户......
  • IIC通信配置时,其GPIO应处于何种工作模式?为何这样做?及IIC总线上为何需增加上拉电阻?其
        直奔主题,以下是以下关于IIC总线应用中所需要理解的特性:1、GPIO应处于何种工作模式?    解:IIC总线通信使用两根新,分别是SDA和SCL,其IO工作模式通常需要配置为开漏输出。因为IIC总线是允许多个设备共享同一总线的,所以所有设备都可以将总线拉低,但不会相互冲突......
  • 02.工厂模式设计思想
    02.工厂模式设计思想目录介绍01.工厂模式设计1.1工厂模式类型1.2工厂模式思考1.3思考一个题目02.简单工厂介绍2.1简单工厂背景2.2简单工厂定义2.3简单工厂结构2.4简单工厂案例2.5简单工厂分析2.6简单工厂场景2.7简单工厂不足03.工厂方法介绍3.1......
  • 了解专用代理服务器的功能
    在当今数字化的环境中,确保安全高效的互联网连接变得至关重要。这种需求催生了专用代理服务器,这是一种确保在线隐私、安全和可访问性的强大工具。了解专用代理服务器的细微差别和功能对于寻求增强在线保护和访问的个人和企业是十分重要的。一、什么是专用代理服务器?专用代理服......
  • RabbitMQ系列学习笔记(三)--工作队列模式
    文章目录一、工作队列模式原理二、工作队列模式实战1、抽取工具类2、消费者代码3、生产者代码4、查看运行结果本文参考尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmqRabbitMQ详解Centos7环境安装Erlang、RabbitMQ详细过程(配图)一、工作队列模式原理与......
  • 前端开发设计模式——命令模式
    目录一、命令模式的定义和特点1.定义:         2. 特点:二、命令模式的结构与原理1.结构:2.原理:三、命令模式的实现方式1.定义接口命令:2.创建具体的命令类:3.定义接收者:4.创建调用者:四、命令模式的使用场景1.界面按钮的点击操作:    1.1 ......
  • Sharding-JDBC标准模式详解
    Sharding-JDBC标准模式详解一.为什么要使用标准模式?Sharding-JDBC的标准模式就配置而言比inline模式繁琐多了,那为什么要使用标准模式呢Sharding-JDBC作为ApacheShardingSphere生态中的一款轻量级Java框架,提供了数据分片、读写分离、分布式事务和数据库治理等核心功......
  • AFLOW:自动化代理工作流生成的未来之路
    ......