代理模式实现

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

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动态代理;

有缺点:

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

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

增加系统复杂度

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

华为HuaweiCloudStack(一)介绍与架构

本文简单介绍了华为HCS私有云解决方案&#xff0c;并从下至上介绍HCS的整体架构&#xff0c;部署架构、部署方式等内容。 目录 HCS简介 HCS架构 纵向结构 ?管理平台类型 HCS节点类型 FusionSphere OpenStack CPS ServiceOM SC 运营面 OC 运维面 HCS部署架构 regi…

【视觉惯性SLAM:十七、ORB-SLAM3 中的跟踪流程】

17.1 跟踪流程流程图 ORB-SLAM3 的跟踪模块是整个系统的重要组成部分&#xff0c;负责实时确定相机在三维空间中的姿态位置&#xff0c;并保持关键帧之间的连续性。其基本目标是将输入的视频流与已有地图数据进行对齐&#xff0c;完成位姿估计和地图更新。 流程图概述 一个…

【机器学习实战入门项目】MNIST数字分类机器学习项目

Python 深度学习项目&#xff1a;手写数字识别 为了使机器更加智能&#xff0c;开发者们正在深入研究机器学习和深度学习技术。人类通过不断练习和重复来学习执行某项任务&#xff0c;从而记住如何完成这些任务。然后&#xff0c;大脑中的神经元会自动触发&#xff0c;他们能够…

Python Pyside6 加Sqlite3 写一个 通用 进销存 系统 初型

图: 说明: 进销存管理系统说明文档 功能模块 1. 首页 显示关键业务数据商品总数供应商总数本月采购金额本月销售金额显示预警信息库存不足预警待付款采购单待收款销售单2. 商品管理 商品信息维护商品编码(唯一标识)商品名称规格型号单位分类进货价销售价库存数量预警…

Ubuntu安装K8S

第一步&#xff1a; 安装docker Install Docker #注意docker是早期的名称已经过时了&#xff0c;因此请使用如下命令&#xff0c;一步到位安装docker-ce。 第二步&#xff1a;设置K8S源&#xff1a; &#xff08;大陆使用aliyun源&#xff0c;大陆外使用google源&#xff09;…

Linux图形界面详解以及替换桌面程序方法

说明&#xff1a;本文章主要说明Linux图形界面的启动流程&#xff0c;以及使用自己的图形化应用替换桌面程序的方法&#xff0c;类似与安卓启动会启动Launcher&#xff0c;使用自己程序替换Launcher一样&#xff0c;实现应用独占系统&#xff0c;或者设计自己的桌面程序。 一、…

第4章 Kafka核心API——Kafka客户端操作

Kafka客户端操作 一. 客户端操作1. AdminClient API 一. 客户端操作 1. AdminClient API

使用 Java 和 FreeMarker 实现自动生成供货清单,动态生成 Word 文档,简化文档处理流程。

在上一篇博客中主要是使用SpringBootApache POI实现了BOM物料清单Excel表格导出&#xff0c;详见以下博客&#xff1a; Spring Boot Apache POI 实现 Exc&#xff08;&#xff09;el 导出&#xff1a;BOM物料清单生成器&#xff08;支持中文文件名、样式美化、数据合并&#…

python编程-OpenCV(图像读写-图像处理-图像滤波-角点检测-边缘检测)边缘检测

OpenCV中边缘检测四种常用算子&#xff1a; &#xff08;1&#xff09;Sobel算子 Sobel算子是一种基于梯度的边缘检测算法。它通过对图像进行卷积操作来计算图像的梯度&#xff0c;并将梯度的大小作为边缘的强度。它使用两个3x3的卷积核&#xff0c;分别用于计…

R语言绘图

多组火山图 数据准备&#xff1a; 将CSV文件同一在一个路径下&#xff0c;用代码合并 确保文件列名正确 library(fs) library(dplyr) library(tidyr) library(stringr) library(ggplot2) library(ggfun) library(ggrepel)# 获取文件列表 file_paths <- dir_ls(path &quo…

IDEA2023版中TODO的使用

介绍&#xff1a;TODO其实本质上还是注释&#xff0c;只不过加上了TODO这几个字符&#xff0c;可以让使用者快速找到。 注意&#xff1a;在类、接口等文件中&#xff0c;注释是使用// 即&#xff1a;// TODO 注释内容 在配置文件中&#xff0c;注释是使用# 即&#xff1a;# TO…

Maven的多模块架构设计诺依的多模块

Maven的多模块架构设计 多模块架构设计&#xff0c;本文采用 诺依的多模块架构设计分析

【JsonViewer】Json格式化

使用 Notepad 对 Json 数据进行格式化处理&#xff0c;使数据在结构上更清晰 1.在线安装 安装之后&#xff0c;重启应用&#xff0c;在插件菜单栏即可看到 JsonViewer 选项&#xff0c;在 Notepad 中放入 Json 数据&#xff0c;点击 Format Json 进行数据格式化 2.离线安装 …

【漏洞预警】FortiOS 和 FortiProxy 身份认证绕过漏洞(CVE-2024-55591)

文章目录 一、产品简介二、漏洞描述三、影响版本四、漏洞检测方法五、解决方案 一、产品简介 FortiOS是Fortinet公司核心的网络安全操作系统&#xff0c;广泛应用于FortiGate下一代防火墙&#xff0c;为用户提供防火墙、VPN、入侵防御、应用控制等多种安全功能。 FortiProxy则…

企业分类相似度筛选实战:基于规则与向量方法的对比分析

文章目录 企业表相似类别筛选实战项目背景介绍效果展示基于规则的效果基于向量相似的效果 说明相关文章推荐 企业表相似类别筛选实战 项目背景 在当下RAG&#xff08;检索增强生成&#xff09;技术应用不断发展的背景下&#xff0c;掌握文本相似算法不仅能够助力信息检索&…

Ubuntu打开文件夹不显示文件

1.情况介绍 使用ubuntu打开文件夹不显示文件夹里面的内容&#xff0c;而是直接打开了资源查看器。 2.解决办法 命令行安装nautilus sudo apt-get install nautilus

Go-知识 版本演进

Go-知识 版本演进 Go release notesr56(2011/03/16)r57(2011/05/03)Gofix 工具语言包工具小修订 r58(2011/06/29)语言包工具小修订 r59(2011/08/01)语言包工具 r60(2011/09/07)语言包工具 [go1 2012-03-28](https://golang.google.cn/doc/devel/release#go1)[go1.1 2013-05-13]…

pycharm+pyside6+desinger实现查询汉字笔顺GIF动图

一、引言 这学期儿子语文期末考试有一道这样的题目&#xff1a; 这道题答案是B&#xff0c;儿子做错了选了C。我告诉他“车字旁”和“车”的笔顺是不一样的&#xff0c;因为二者有一个笔画是不一样的&#xff0c;“车字旁”下边那笔是“提”&#xff0c;而“车”字是“横”&am…

Red Hat8:搭建DHCP服务器

1、新建挂载文件 2、挂载 3、关闭防火墙 4、搭建yum源 &#xff08;搭建的时候用vim 自行定义文件名.repo或者是vi 自行定义文件名.repo&#xff09; 5、安装dhcp-server 6、复制模板文件 dhcpd.conf 是DHCP服务的配置文件&#xff0c;DHCP服务所有参数都是通过修改dhcpd.co…

Web前端------HTML链接标签

1.普通超链接 &#xff08;1&#xff09;链接外部网页 点击文本&#xff0c;跳转到外部网页 <!DOCTYPE html><html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, i…