Mybatis---代理设计模式(超详细)

Mybatis—代理设计模式

文章目录

  • Mybatis---代理设计模式
    • 一、什么是代理设计模式
    • 二、静态代理
      • 1、定义
      • 2、结构
      • 3、示例
    • 三、动态代理
      • 1、定义
      • 2、newProxyInstance ()方法
      • 3、示例
    • 四、CGLIB代理
      • 1、引入
      • 2、定义
      • 3、工作原理
      • 4、示例

一、什么是代理设计模式

首先需要知道什么是设计模式:

设计模式:为了实现某一个功能 前人总结出的一个好的方法和步骤

代理设计模式: 一种结构型设计模式,主要用于为其他对象提供一种代理,以控制对这个对象的访问。代理模式通常用于延迟对象的加载、控制对资源的访问,或者在不修改原始类的情况下对功能进行扩展。

代理的设计模式 是为了解决什么问题呢?

他可以动态的监控一个类中 方法在什么时候 执行 以及可以在方法执行的前后 动态植入我们的代码

注意:静态代理 和 动态代理都有一个代理的前提 就是我们的被代理的类 一定要实现接口 或者自己就是接口

说白了 代理的设计模式 最终的目的 就是对类中的方法进行增强

二、静态代理

1、定义

静态代理 是代理模式的一种实现方式,在编译时通过明确的代理类来控制对真实对象的访问。静态代理通常需要手动编写代理类,它在功能上可以对原有对象的功能进行扩展,而不需要修改原始类的代码。与动态代理相比,静态代理的结构较为简单,但代码的可复用性不高。

2、结构

  1. 接口(Subject):定义了代理对象和真实对象的通用行为,代理对象和真实对象都需要实现该接口。
  2. 真实对象(Real Subject):实际执行业务逻辑的对象。
  3. 代理对象(Proxy):持有真实对象的引用,并通过它来控制对真实对象的访问。代理对象可以在调用真实对象的方法前后添加额外的操作。

3、示例

需求:就是Service类中所有方法在执行之前都需要 输出一句话 打开事务;在所有方法执行完成之后 我们都需要输出一句话 关闭和提交事务。

3.1、编写接口

public interface IUserService {/*** 更新的方法*/void update();/*** 添加数据的方法*/void add();
}

3.2、编写接口实现类

package com.qfedu.edu.proxy.static1;/*** @author xiaobobo* @title: UserService* @projectName cd-java-fy-2401-framwork-demo* @description: 这个类就成为被代理的类* 现在我们有一个要求:*    就是Service类中所有方法在执行之前都需要 输出一句话 打开事务*    在所有方法执行完成之后  我们都需要输出一句话  关闭和提交事务* @date 2024/9/3  14:45*/
public class UserService implements IUserService {public void update() {System.out.println("更新完成");}public void add() {System.out.println("添加完成....");}}

3.3、编写代理类

package com.qfedu.edu.proxy.static1;import static com.qfedu.edu.proxy.utils.TransactionUtils.*;/*** @author xiaobobo* @title: UserServiceProxy* @projectName cd-java-fy-2401-framwork-demo* @description: 静态代理的第一步:编写一个代理类和被代理的类实现相同的接口* @date 2024/9/3  14:49*/
public class UserServiceProxy implements IUserService {//静态代理的第二步:在代理类中维护被代理类的对象private IUserService userService;//静态代理的第三步:在构造器中去实例化这个成员变量public UserServiceProxy(IUserService userService) {this.userService = userService;}//静态代理的第四步:在代理中的方法中 调用被代理类 相同名字的方法public void update() {beginTransaction();this.userService.update();closeCommitTransaction();}public void add() {beginTransaction();this.userService.add();closeCommitTransaction();}
}

3.4、编写测试类

public class Test001 {@Testpublic void testProxy() {UserServiceProxy userServiceProxy = new UserServiceProxy(new UserService());userServiceProxy.add();}
}

输出结果:

在这里插入图片描述

三、动态代理

1、定义

允许在运行时动态生成代理类,而不是在编译时确定。这在 Java 等支持反射的编程语言中非常常见。代理模式的核心思想是通过代理对象来控制对目标对象的访问,而动态代理则进一步增强了这种控制的灵活性。

理解动态代理又名 JDK代理 简单的说 就是整个代理的过程JDK帮你实现了 你直接用就可以了…

经验: 在 Java 中,动态代理通常通过 java.lang.reflect.Proxy 类和 InvocationHandler 接口实现。使用动态代理,代理类不需要预先定义,而是通过 Proxy.newProxyInstance() 方法在运行时动态创建。

2、newProxyInstance ()方法

动态代理的核心方法 Proxy.newProxyInstance() , 它用于在运行时生成代理对象。它允许你创建实现一个或多个接口的代理对象,而无需预先定义代理类。这个方法属于 java.lang.reflect.Proxy 类。

参数说明

第一个参数是类加载器 :固定写法 被代理的类.class.getClassLoader
第二个参数是被代理的类实现的接口
1、如果被代理的是类
类.class.getInterfaces()
2、如果被代理的是接口
new Class[]{接口.class}
第三个参数:回调函数
JDK代理实际上生成的是 接口的实现类 兄弟关系
在JDK代理中第三个参数是最重要的 因为可以监控方法在什么时候执行

工作原理

当你调用 newProxyInstance() 方法时,它会在运行时生成一个代理类,该类实现了指定的接口,并将所有方法调用委托给 InvocationHandler。代理类在调用接口方法时,会转发调用到 InvocationHandlerinvoke() 方法。

3、示例

2.1、编写接口

package com.qfedu.edu.proxy.dynamic;/*** @author xiaobobo* @title: IUserService* @projectName cd-java-fy-2401-framwork-demo* @description: 这个是被代理的类实现的接口* @date 2024/9/3  14:44*/
public interface IUserService {/*** 更新的方法*/void update();/*** 添加数据的方法*/void add();
}

2.2、编写被代理类

public class UserService implements IUserService {public void update() {System.out.println("更新完成");}public void add() {System.out.println("添加完成....");}}

2.3、测试代理类

package com.qfedu.edu.proxy.dynamic;import com.qfedu.edu.proxy.utils.TransactionUtils;
import org.junit.Test;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author xiaobobo* @title: Test001* @projectName cd-java-fy-2401-framwork-demo* @description: TODO* @date 2024/9/3  15:19*/
public class Test001 {/*** 测试动态代理的地方*/@Testpublic void testDynamicProxy() {//首先生成代理类对象/*** 第一个参数是类加载器 :固定写法  被代理的类.class.getClassLoader* 第二个参数是被代理的类实现的接口*       1>、如果被代理的是类*           类.class.getInterfaces()*       2>、如果被代理的是接口*           new Class[]{接口.class}* 第三个参数:回调函数* JDK代理实际上生成的是 接口的实现类 兄弟* 在JDK代理中第三个参数是最重要的 因为可以监控方法在什么时候执行*/IUserService userServiceProxy = (IUserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),UserService.class.getInterfaces(),new InvocationHandler() {/*** 这个方法就是监控被代理类中 方法在什么时候执行的回调函数*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String name = method.getName();System.out.println("当前执行的方法的名字是:" + name);TransactionUtils.beginTransaction();//放行执行到目标类中去(这个类的实例 应该是目标类对象)Object invoke = method.invoke(new UserService(), args);TransactionUtils.closeCommitTransaction();return invoke;}});userServiceProxy.update();}}

2.4、模拟生成的代理类对象

package com.qfedu.edu.proxy.dynamic;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** @author xiaobobo* @title: UserServiceProxy* @projectName cd-java-fy-2401-framwork-demo* @description: 反推出这个代理类 应该长啥样?* @date 2024/9/3  15:30*/
public class UserServiceProxy implements IUserService {//相当于把这个接口传递过来了(这个相当于是爹的这个class对象)private Class interfaces;private InvocationHandler invocationHandler;public UserServiceProxy(Class interfaces, InvocationHandler invocationHandler) {this.interfaces = interfaces;this.invocationHandler = invocationHandler;}public void update() {//这里怎么做呢?//通过父亲(接口) 去找他爹里面相同名字的方法(反射)//这个method是谁里面的method? 爹里面的methodtry {Method method = interfaces.getMethod("update");//接下来怎么做呢?this.invocationHandler.invoke(this, method, null);} catch (Throwable e) {throw new RuntimeException(e);}}public void add() {//这里怎么做呢?//通过父亲(接口) 去找他爹里面相同名字的方法(反射)//这个method是谁里面的method? 爹里面的methodtry {Method method = interfaces.getMethod("add");//接下来怎么做呢?this.invocationHandler.invoke(this, method, null);} catch (Throwable e) {throw new RuntimeException(e);}}
}

输出结果:
在这里插入图片描述

四、CGLIB代理

1、引入

有个问题:

就是不论咋们的静态代理 还是 CGLIB代理 都有一个代理的前提

这个代理的前提是:被代理的类 必须实现接口 或者本身就是接口

假设现在有一个类 没有实现接口 但是我们依然想给他进行功能的拓展 我们怎么办呢?

于是CGLIB代理就应运而生了…

记住CGLIB代理的代理类 肯定不需要我们去实现了 只是需要我们去获取代理类对象就可以了 跟JDK代理是一样的

但是这个CGLIB代理类生成的是 子类 生成的是 被代理类的子类

2、定义

CGLIB 代理 是另一种实现代理设计模式的技术,与 Java 自带的动态代理 (Proxy.newProxyInstance()) 不同,CGLIB 是通过生成目标类的子类来创建代理对象,而不是基于接口代理。这使得 CGLIB 能够代理 没有实现接口的类,解决了 JDK 动态代理只能代理接口的局限性。

CGLIB 全称是 Code Generation Library,它在运行时生成字节码,并动态创建目标类的子类。因此,CGLIB 代理的本质是通过继承来实现的。

3、工作原理

  1. 生成子类:CGLIB 通过 ASM 字节码操作框架,生成目标类的子类来实现代理。
  2. 方法拦截:CGLIB 使用 MethodInterceptor 来拦截对目标方法的调用,类似于 JDK 动态代理中的 InvocationHandler

4、示例

4.1、导包

<!--        这个就是咋们的CGLIb代理需要的这个包--><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.4</version></dependency>

4.2、编写被代理类

public class UserService{public void update() {System.out.println("更新完成");}public void add() {System.out.println("添加完成....");}}

4.3、编写工厂

package com.qfedu.edu.proxy.cglib;import com.qfedu.edu.proxy.utils.TransactionUtils;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @author xiaobobo* @title: UserServiceProxyFactory* @projectName cd-java-fy-2401-framwork-demo* @description: 这个类的主要作用是进行CGLIB代理类的生产* @date 2024/9/4  9:29*/
public class UserServiceProxyFactory implements MethodInterceptor {/*** 这个方法的主要作用就是生成咋们的这个代理类对象** @return*/public UserService getUserServiceProxy() {Enhancer enhancer = new Enhancer();//设置他爹是谁enhancer.setSuperclass(UserService.class);//设置这个拦截对象enhancer.setCallback(this);return (UserService) enhancer.create();}/*** 这个方法主要就是为了实现这个方法执行时候的拦截的** @param o* @param method* @param objects* @param methodProxy* @return* @throws Throwable*/public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//这里你就可以对方法进行增强了TransactionUtils.beginTransaction();Object invoke = method.invoke(new UserService(), objects);TransactionUtils.closeCommitTransaction();return invoke;}
}

4.4、编写测试

package com.qfedu.edu.proxy.cglib;import org.junit.Test;/*** @author xiaobobo* @title: Test001* @projectName cd-java-fy-2401-framwork-demo* @description: TODO* @date 2024/9/4  9:37*/
public class Test001 {@Testpublic void testCGLIB() {UserService userServiceProxy = new UserServiceProxyFactory().getUserServiceProxy();userServiceProxy.update();}
}

输出结果:
在这里插入图片描述

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

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

相关文章

EmguCV学习笔记 C# 9.2 VideoWriter类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

『功能项目』Unity本地数据库读取进入游戏【29】

本章项目成果展示 打开上一篇28Unity连接读取本地数据库的项目&#xff0c; 本章要做的事情是通过读取本地数据库登录进入游戏场景 首先创建一个脚本文件夹&#xff1a; 新建脚本&#xff1a;MySqlAccess.cs 编写脚本&#xff1a;MySqlAccess.cs using UnityEngine; using MyS…

uniapp scroll-view滚动页面

页面滚动固定距离&#xff08;scrollTop&#xff09; <template><view><button click"Test">测试</button><scroll-view style"height: 100px;" :scroll-top"scrollTop" scroll-y"true" class"scrol…

FME教程:通过更新读模块,解决FME读取shapefile数据,提示意外输入,“在转换中,某些读取的要素与工作空间的要素类不匹配……”的问题

目录 一、问题情况 二、解决方法 一、问题情况 在使用制作好的FME模板读取shapefile数据时&#xff0c;有时候会遇到弹窗提示意外输入&#xff0c;模板无法运行&#xff0c;在日志信息中警示“在转换中&#xff0c;某些读取的要素与工作空间的要素类不匹配。可能由于读模块的…

鸿蒙轻内核M核源码分析系列十三 消息队列Queue

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 轻内核M核源码分析系列一 数据结构-双向循环链表 轻内核M核源码分析系列二 数据结构-任务就绪队列 鸿蒙轻内核M核源码分析系列三 数据结构-任务排序链表 轻…

Unity TMP (TextMeshPro) 更新中文字符集

TMP更新中文字符集 1 字符集缺失说明2 字体的字符表2.1 字符表更新模式&#xff1a;动态2.2 字符表更新模式&#xff1a;静态 3 更新字符集步骤3.1 打开纹理更新面板3.1 导入文本文件3.3 关于警告处理 4 修改TMP默认字体设置 1 字符集缺失说明 使用TMP显示中文需要用到中文字体…

数据预处理与协同过滤推荐算法——从数据清洗到个性化电影推荐

推荐系统在现代应用中占据了重要地位&#xff0c;尤其在电影、音乐等个性化内容推荐中广泛使用。本文将介绍如何使用数据预处理、特征工程以及多种推荐算法&#xff08;包括协同过滤、基于内容的推荐、混合推荐等&#xff09;来实现电影推荐系统。通过Pandas、Scikit-learn、Te…

etcdctl defrag 剔除、添加etcd节点

零、准备工作 find / -name etcdctl cp /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/12/fs/usr/local/bin/etcdctl /usr/local/bin/etcdctlalias ec"etcdctl --endpointshttps://127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --…

利用正则表达式从字符串中提取浮点数

在 Python 中&#xff0c;使用正则表达式可以非常方便地从字符串中提取浮点数。Python 的 re 模块提供了正则表达式支持。下面是如何使用正则表达式提取浮点数的示例。 1、问题背景 在开发过程中&#xff0c;有时候我们需要从字符串中提取浮点数&#xff0c;例如从 HTML 代码中…

网关功能介绍

在微服务架构中&#xff0c;网关&#xff08;API Gateway&#xff09;扮演着至关重要的角色&#xff0c;它作为客户端和微服务之间的中介&#xff0c;负责路由、过滤、认证、限流等职责。以下是一些常见的网关实现&#xff1a; Spring Cloud Gateway&#xff1a; Spring Cloud …

linux系统中,计算两个文件的相对路径

realpath --relative-to/home/itheima/smartnic/smartinc/blocks/ruby/seanet_diamond/tb/parser/test_parser_top /home/itheima/smartnic/smartinc/corundum/fpga/lib/eth/lib/axis/rtl/axis_fifo.v 检验方式就是直接在当前路径下&#xff0c;把输出的路径复制一份&#xff0…

5-2 检测内存容量

1 使用的是bios 中断&#xff0c; 每次进行检测都会返回一块 内容。并且标志上&#xff0c;这块内存是否可用。 接下来是代码&#xff1a; 首先是构建 一个文件夹&#xff0c; 两个文件。 types.h 的内容。 #ifndef TYPES_H #define TYPES_H// 基本整数类型&#xff0c;下面的…

全球圆柱锂电池行业领军者!比克电池亮相2024深圳eVTOL展

2024深圳eVTOL产业发展大会暨低空经济展览会将于9月23-25日在深圳坪山燕子湖国际会展中心举办。展会将通过“两天论坛三天展览”的形式展开&#xff0c;专注未来城市空中交通新形态、民用有人驾驶、无人驾驶航空器、城市低空物流&#xff0c;并讨论eVTOL的整机研发、设计、制造…

拍卖新纪元:Spring Boot赋能在线拍卖解决方案

需求分析 1.1技术可行性&#xff1a;技术背景 在线拍卖系统是在Windows操作系统中进行开发运用的&#xff0c;而且目前PC机的各项性能已经可以胜任普通网站的web服务器。系统开发所使用的技术也都是自身所具有的&#xff0c;也是当下广泛应用的技术之一。 系统的开发环境和配置…

Python+selenium web测试入门基础!

自动化测试框架 from selenium import webdriver 获取浏览器对象 我这里是edge浏览器&#xff0c;用的是edge的webdriver # webdriver获取浏览器对象  driver webdriver.Edge() 尝试打开网站并关闭​​​​​​​ # 准备一个网址  url "https://www.baidu.com/"…

包拯断案 | 数据库从库GTID在变化 为何没有数据写入@还故障一个真相

提问&#xff1a;作为DBA运维的你是否遇到过这些烦恼 1、数据库从库复制链路如何正确配置表过滤信息&#xff1f; 2、数据库从库的GTID在变化&#xff0c;实际却没有数据写入&#xff0c;究竟是什么原因&#xff1f; 心中有章&#xff0c;遇事不慌 作为DBA的你&#xff0c;…

如何构建短视频矩阵?云微客开启多账号协同作战

你有没有疑惑过&#xff0c;为什么有些账号每一次发布视频&#xff0c;都要艾特一下其他账号呢&#xff1f;那些被艾特的账号&#xff0c;你有点进去关注过吗&#xff1f;其实做过运营的都或多或少的接触过矩阵&#xff0c;短视频矩阵的玩法现在也逐步成为了趋势。企业通过多账…

pyautogui进行点击失效,pyautogui.click()失效

背景&#xff1a;在Pycharm里&#xff0c;使用pythonpyautogui调用 .exe程序文件时候&#xff0c;当程序界面出来之后&#xff0c;鼠标失去反应&#xff0c;用pyautogui进行点击。后面尝试使用图片相似也无法实行点击。 解决方法&#xff1a;运行Pycharm或者其他ide的时候选择…

黑马点评2——商户查询缓存(P37店铺类型查询业务添加缓存练习题答案)redis缓存、更新、穿透、雪崩、击穿、工具封装

文章目录 什么是缓存&#xff1f;添加Redis缓存店铺类型查询业务添加缓存练习题 缓存更新策略给查询商铺的缓存添加超时剔除和主动更新的策略 缓存穿透缓存空对象布隆过滤 缓存雪崩解决方案 缓存击穿解决方案基于互斥锁方式解决缓存击穿问题基于逻辑过期的方式解决缓存击穿问题…

极市开发平台yolov8训练无人机数据集样例数据流程

先进入vscode&#xff0c;进入src_repo文件夹。 第一步&#xff0c;克隆一个比较好的博主的库&#xff1a; GitHub - Incalos/YOLO-Datasets-And-Training-Methods: This project involves making custom datasets for the YOLO series and model training methods for YOLO.…