代理模式实现

news2025/1/19 1:35:22

一、概念:代理模式属于结构型设计模式。客户端不能直接访问一个对象,可以通过代理的第三者来间接访问该对象,代理对象控制着对于原对象的访问,并允许在客户端访问对象的前后进行一些扩展和处理;这种设置模式称为代理模式;

2个点:

由代理对象去控制对原对象的访问(方法调用),客户端不直接对原对象进行访问,比如数据库的访问,不由Controller去控制;

在访问原对象时,可以有代理对象对原对象的功能(方法)进行扩展,比如访问数据库时,可以在代理对象里面进行开启事务和提交事务或回滚事务;

二、UML类图:

三、实现

1、静态代理实现

/**
 * Subject
 */
public interface IUserMapperInterface {

    void save(String userName, String userNumber);
}

/**
 * RealSubject
 */
public class UserMapperInterfaceImpl implements IUserMapperInterface {

    @Override
    public void save(String userName, String userNumber) {
        System.out.println("执行insert语句,保存数据,并返回成功!");
    }
}

/**
 * 代理类
 */
public class UserMapperInterfaceProxy implements IUserMapperInterface {

    private IUserMapperInterface userMapperInterface;

    public UserMapperInterfaceProxy(IUserMapperInterface userMapperInterface) {
        this.userMapperInterface = userMapperInterface;
    }

    @Override
    public void save(String userName, String userNumber) {
        System.out.println("开启事务~~~");
        userMapperInterface.save(userName, userNumber);
        System.out.println("提交事务");
    }
}

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        String userName = "user name";
        String userNumber = "user number";

        UserMapperInterfaceProxy proxy = new UserMapperInterfaceProxy(new UserMapperInterfaceImpl());
        proxy.save(userName, userNumber);

    }
}

优缺点:

优点:可以在不修改目标类的前提下,对目标类进行扩展

缺点:

代码冗余,代理对象实现了和目标对象一致的接口,产生了一些冗余接口;

一旦目标接口中增加了新的方法,那么代理对象和真实接口实现都需要修改代码才行;

2、动态代理的实现:

动态代理与静态代理的区别:

静态代理在类加载完经已经加载JVM中,并且如有其他对象需要加载,需要修改代理对象;

动态代理只有在运行的时候才会去加载目标类, 当需要加载其他对象的时候,不需要修改,也就是动态代理可以代理任何对象Object;

动态代理有两种实现方式:JDK动态代理,和CGLib动态代理

  • JDK的动态代理,通过动态的生成一个接口对象的实现实例来实现对接口对象实例的功能扩展,在JDK的动态代理实现中,目标对象必须实现一个接口;
  • 通过反射包下的Proxy.newProxyInstance()方法实现

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 getTargetInstance() {

        //Proxy是反射包下(java.lang.reflect)的一个代理类,通过这个类的newProxyInstance(新建代理对象实例)来动态的加载一个代理目标对象,并返回
        //newProxyInstance方法需要传递三个参数,1、目标对象的类加载器, 2、目标对象实现的接口(如果有实现就有,没有实现就没有),3、目标对象需要执行的方法,相当于扩展静态代理中的那个save方法
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            //,目标对象被代理后需要执行的扩展方法,也有三个参数,1、目标对象,2、目标对象需要执行的方法实例,3、方法实例需要传递的参数
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("开启一个事务~!");
                //执行方法,执行的时候把目标对象和方法参数传递过去
                method.invoke(target, args);

                System.out.println("提交事务");

                //返回值是指目标执行的方法的返回值,如果没有就返回null,在静态代理中,目标方法save的返回值是void,因此这里返回null
                return null;
            }
        });
    }
}

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        String userName = "user name";
        String userNumber = "user number";


        //使用静态代理的模式实现代理,此时在类加载的时候就会创建该对象
        UserMapperInterfaceProxy proxy = new UserMapperInterfaceProxy(new UserMapperInterfaceImpl());
        proxy.save(userName, userNumber);
        System.out.println("静态代理实现的类名:" + proxy.getClass().getName());

        //使用动态代理的模式实现代理功能,在类加载的时候不会创建对象,在运行过程中才会去创建对象并调用对象 的方法
        ProxyFactory proxyFactory = new ProxyFactory(new UserMapperInterfaceImpl());
        IUserMapperInterface targetInstance = (IUserMapperInterface) proxyFactory.getTargetInstance();
        targetInstance.save(userName, userNumber);
        System.out.println("动态代理实现的类名:" + targetInstance.getClass().getName());
    }
}
  • CGLib动态代理的实现

CGLib是一个第三方的代码生成类库,运行时在内存中生成一个子类继承目标对象,从而实现对目标对象的扩展;SpringAOP和Hibernate都是基于CGLib动态代理实现的,而CGlib又是通过封装ASM工具包去操作字节码的;

引入包:如果是Spring项目,则不需要单独引入,SpringCore里面已经包含该包

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

目标类:


/**
 * CGLib方式实现代理的目标类
 */
public class CGLibTargetClass {

    public void targetMethod(String userName, String userNumber) {
        System.out.println("CGLibTargetClass targetMethod");
        System.out.println("保存用户信息:username=" + userName + ",usernumber=" + userNumber);
    }
}

代理类:实现MethodInterceptor接口,并重写interceptor方法,

public class CGLibProxyIntercept implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("保存用户信息前开启事务");
        System.out.println(objects.toString());
        System.out.println(o.getClass().getName());
        methodProxy.invokeSuper(o, objects);
        System.out.println("保存用户信息后提交事务");
        return o;
    }
}

代理模式的总结:

由于CGlib采用的是继承目标类的方式去进行增强的,因此对于final类或方法是不能被继承的,无法使用CGlib的方式进行代理;

在jdk1.8后,实际上JDK动态代理比CGLib动态代理效率高,但JDK动态代理需要目标类实现一个接口,因此如果对象有实现接口,用JDK动态代理,没实现 用CGLib动态代理;

有缺点:

在客户端与目标对象之间起到中介作用,保护目标对象

对目标对象进行扩展,将客户端与目标对象分离,解耦

增加系统复杂度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2278713.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

回归预测 | MATLAB实TCN时间卷积神经网络多输入单输出回归预测

效果一览 基本介绍 回归预测 | MATLAB实TCN时间卷积神经网络多输入单输出回归预测 …………训练集误差指标………… 1.均方差(MSE)&#xff1a;166116.6814 2.根均方差(RMSE)&#xff1a;407.5741 3.平均绝对误差&#xff08;MAE&#xff09;&#xff1a;302.5888 4.平均相对…

《目标检测数据集下载地址》

一、引言 在计算机视觉的广袤领域中&#xff0c;目标检测宛如一颗璀璨的明星&#xff0c;占据着举足轻重的地位。它宛如赋予计算机一双锐利的 “眼睛”&#xff0c;使其能够精准识别图像或视频中的各类目标&#xff0c;并确定其位置&#xff0c;以边界框的形式清晰呈现。这项技…

Android系统定制APP开发_如何对应用进行系统签名

前言 当项目开发需要使用系统级别权限或frame层某些api时&#xff0c;普通应用是无法使用的&#xff0c;需要在AndroidManifest中配置sharedUserId&#xff1a; AndroidManifest.xml中的android:sharedUserId“android.uid.system”&#xff0c;代表的意思是和系统相同的uid&a…

【NextJS】PostgreSQL 遇上 Prisma ORM

NextJS 数据库 之 遇上Prisma ORM 前言一、环境要求二、概念介绍1、Prisma Schema Language&#xff08;PSL&#xff09; 结构描述语言1.1 概念1.2 组成1.2.1 Data Source 数据源1.2.2 Generators 生成器1.2.3 Data Model Definition 数据模型定义字段(数据)类型和约束关系&…

Mybatis 进阶 / Mybatis—Puls (详细)

目录 一.动态SQL 1.1标签 1.2 标签 1.3标签 1.4标签 1.5标签 1.6标签 mybatis总结&#xff1a; 二.Mybatis-Puls 2.1准备工作 2.2CRUD单元测试 2.2.1创建UserInfo实体类 2.2.2编写Mapper接⼝类 2.2.3 测试类 2.3 常见注解 2.3.1TableName 2.3.2TableField 2.4打印日…

Java工具包:高效开发的魔法钥匙

目录 一、引言 二、Hutool 工具包初体验 2.1 快速入门 2.2 常用工具类及方法详解 2.2.1 Convert 类型转换工具类 2.2.2 DateUtil 日期时间工具类 2.2.3 StrUtil 字符串工具类 2.2.4 其他常用工具类 三、其他 Java 常用工具包巡礼 3.1 Apache Commons 系列 3.2 Google…

Formality:参考设计/实现设计以及顶层设计

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482​​​ Formality存在两个重要的概念&#xff1a;参考设计/实现设计和顶层设计&#xff0c;本文就将对此进行详细阐述。参考设计/实现设计是中两个重要的全局概念&am…

HBase实训:纸币冠字号查询任务

一、实验目的 1. 理解分布式数据存储系统HBase的架构和工作原理。 2. 掌握HBase表的设计原则&#xff0c;能够根据实际业务需求设计合理的表结构。 3. 学习使用HBase Java API进行数据的插入、查询和管理。 4. 实践分布式数据存储系统在大数据环境下的应用&#xff0c;…

C#轻松实现条形码二维码生成及识别

一、前言 大家好&#xff01;我是付工。 今天给大家分享一下&#xff0c;如何基于C#来生成并识别条形码或者二维码。 二、ZXing.Net 实现二维码生成的库有很多&#xff0c;我们这里采用的是http://ZXing.Net。 ZXing是一个开放源码的&#xff0c;用Java实现的多种格式的一…

重拾Python学习,先从把python删除开始。。。

自己折腾就是不行啊&#xff0c;屡战屡败&#xff0c;最近终于找到前辈教我 第一步 删除Python 先把前阵子折腾的WSL和VScode删掉。还是得用spyder&#xff0c;跟matlab最像&#xff0c;也最容易入手。 从VScode上搞python&#xff0c;最后安装到appdata上&#xff0c;安装插…

ASP.NET Core - 依赖注入(三)

ASP.NET Core - 依赖注入&#xff08;三&#xff09; 4. 容器中的服务创建与释放 4. 容器中的服务创建与释放 我们使用了 IoC 容器之后&#xff0c;服务实例的创建和销毁的工作就交给了容器去处理&#xff0c;前面也讲到了服务的生命周期&#xff0c;那三种生命周期中对象的创…

高通8255 Android STR 启动失败要因分析调查

目录 背景&#xff1a; 调查过程&#xff1a; 步骤1&#xff1a; slog2info | grep vmm_service 步骤2&#xff1a; slog2info | grep qvm 总结&#xff1a; 解决方案 背景&#xff1a; 调试高通8255 STR的STR过程中发现Android和QNX进入STR状态后&#xff0c;脱出STR时…

Linux操作命令之云计算基础命令

一、图形化界面/文本模式 ctrlaltF2-6 图形切换到文本 ctrlalt 鼠标跳出虚拟机 ctrlaltF1 文本切换到图形 shift ctrl "" 扩大 ctrl "-" 缩小 shift ctrl "n" 新终端 shift ctrl "t" 新标签 alt 1,…

LabVIEW桥接传感器配置与数据采集

该LabVIEW程序主要用于配置桥接传感器并进行数据采集&#xff0c;涉及电压激励、桥接电阻、采样设置及错误处理。第一个VI&#xff08;"Auto Cleanup"&#xff09;用于自动清理资源&#xff0c;建议保留以确保系统稳定运行。 以下是对图像中各个组件的详细解释&#…

面试题解析

1、写一个sed命令&#xff0c;修改/tmp/input.txt文件的内容 要求&#xff1a; 删除所有空行&#xff1b; 在非空行前面加一个"AAA"&#xff0c;在行尾加一个"BBB"&#xff0c;即将内容为11111的一行改为&#xff1a;AAA11111BBB 创造测试文件&#xff1a;…

合合信息名片全能王上架原生鸿蒙应用市场,成为首批数字名片类应用

长期以来&#xff0c;名片都是企业商务沟通的重要工具。随着企业数字化转型&#xff0c;相较于传统的纸质名片&#xff0c;数字名片对于企业成员拓展业务、获取商机、提升企业形象等方面发挥着重要作用。近期&#xff0c;合合信息旗下名片全能王正式上线原生鸿蒙应用市场&#…

【日志篇】(7.6) ❀ 01. 在macOS下刷新FortiAnalyzer固件 ❀ FortiAnalyzer 日志分析

【简介】FortiAnalyzer 是 Fortinet Security Fabric 安全架构的基础&#xff0c;提供集中日志记录和分析&#xff0c;以及端到端可见性。因此&#xff0c;分析师可以更有效地管理安全状态&#xff0c;将安全流程自动化&#xff0c;并快速响应威胁。具有分析和自动化功能的集成…

《汽车维修技师》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答&#xff1a; 问&#xff1a;《汽车维修技师》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《汽车维修技师》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;北方联合出版传媒&#xff08;…

【OpenCV(C++)快速入门】--opencv学习

0 配置环境 配置环境网上很多资料&#xff0c;这里就不赘述了。 笔者使用的是VS2022opencv4.9.0 测试配置环境 // 打开摄像头样例 #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgcodecs/imgcod…

Python编程与在线医疗平台数据挖掘与数据应用交互性研究

一、引言 1.1 研究背景与意义 在互联网技术飞速发展的当下,在线医疗平台如雨后春笋般涌现,为人们的就医方式带来了重大变革。这些平台打破了传统医疗服务在时间和空间上的限制,使患者能够更加便捷地获取医疗资源。据相关报告显示,中国基于互联网的医疗保健行业已进入新的…