网站gif图标/湖南广告优化

网站gif图标,湖南广告优化,医药公司网站备案,wordpress编码简介 插件是一种常见的扩展方式,大多数开源框架也都支持用户通过添加自定义插件的方式来扩展或者改变原有的功能,MyBatis中也提供的有插件,虽然叫插件,但是实际上是通过拦截器(Interceptor)实现的,在MyBatis的插件模块…

简介

插件是一种常见的扩展方式,大多数开源框架也都支持用户通过添加自定义插件的方式来扩展或者改变原有的功能,MyBatis中也提供的有插件,虽然叫插件,但是实际上是通过拦截器(Interceptor)实现的,在MyBatis的插件模块中涉及到责任链模式和JDK动态代理。

如何自定义实现插件?

step1:实现Interceptor接口;

step2:配置拦截器在全局配置文件

<plugins><plugin interceptor="com.dura.interceptor.FirstInterceptor"><-- 这里的这个属性,我没写哈;不过,这里的用法倒是挺重要的,定义在拦截器中属性  --><property name="testProp" value="1000"/></plugin></plugins>

step3:运行。

插件实现的原理?

初始化操作——全局配置文件解析

该方法用来解析全局配置文件中的plugins标签,然后对应的创建Interceptor对象,并且封装对应的属性信息。最后调用了Configuration对象中的方法。 configuration.addInterceptor(interceptorInstance)

通过这个代码我们发现我们自定义的拦截器最终是保存在了InterceptorChain这个对象中。而InterceptorChain的定义为

创建代理对象过程?

在解析的时候创建了对应的Interceptor对象,并保存在了InterceptorChain中,那么这个拦截器是如何和对应的目标对象进行关联的呢

首先拦截器可以拦截的对象是Executor,ParameterHandler,ResultSetHandler,StatementHandler。

那么我们来看下这四个对象在创建的时候又什么要注意的

Executor

Executor在装饰完二级缓存后会通过pluginAll来创建Executor的代理对象。

StatementHandler

  @Overridepublic <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {Configuration configuration = ms.getConfiguration();// 注意,已经来到SQL处理的关键对象 StatementHandlerStatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);// 获取一个 Statement对象stmt = prepareStatement(handler, ms.getStatementLog());// 执行查询return handler.query(stmt, resultHandler);} finally {// 用完就关闭closeStatement(stmt);}}// 进入创建的方法public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);// 植入插件逻辑(返回代理对象)statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}//  可以看到statementHandler的代理对象

ParameterHandler

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {// StatementType 是怎么来的? 增删改查标签中的 statementType="PREPARED",默认值 PREPAREDswitch (ms.getStatementType()) {case STATEMENT:delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;case PREPARED:// 创建 StatementHandler 的时候做了什么? >>delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;case CALLABLE:delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;default:throw new ExecutorException("Unknown statement type: " + ms.getStatementType());}}// 进入某个Handler看下  
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);// 植入插件逻辑(返回代理对象)parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;}

ResultSetHandler

  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,ResultHandler resultHandler, BoundSql boundSql) {ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);// 植入插件逻辑(返回代理对象)resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);return resultSetHandler;}

执行过程

以Executor的query方法为例,当查询请求到来的时候,Executor的代理对象是如何处理拦截请求的呢?我们来看下。当请求到了executor.query方法的时候


// 执行Plugin的invoke 方法
/*** 代理对象方法被调用时执行的代码* @param proxy* @param method* @param args* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 获取当前方法所在类或接口中,可被当前Interceptor拦截的方法Set<Method> methods = signatureMap.get(method.getDeclaringClass());if (methods != null && methods.contains(method)) {// 当前调用的方法需要被拦截 执行拦截操作return interceptor.intercept(new Invocation(target, method, args));}// 不需要拦截 则调用 目标对象中的方法return method.invoke(target, args);} catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);}}//然后进入interceptor.intercept 会进入我们自定义的 FirstInterceptor对象中/*** 执行拦截逻辑的方法* @param invocation* @return* @throws Throwable*/@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("FirtInterceptor  拦截之前 ....");Object obj = invocation.proceed(); // 执行目标方法System.out.println("FirtInterceptor  拦截之后 ....");return obj;}

以上就是自定义的拦截器执行的完整流程。

如果我们有多个拦截器怎么办

如果我们有多个自定义的拦截器,那么他的执行流程是怎么样的呢?比如我们创建了两个 Interceptor 都是用来拦截 Executor 的query方法,一个是用来执行逻辑A 一个是用来执行逻辑B的。

总结:Interceptor的相关对象作用

对象作用
Interceptor自定义插件需要实现接口,实现4个方法
InterceptChain配置的插件解析后会保存在Configuration的InterceptChain中
Plugin触发管理类,还可以用来创建代理对象
Invocation对被代理类进行包装,可以调用proceed()调用到被拦截的方法

应用场景分析——其实在说拦截器啦

作用描述实现方式
水平分表一张费用表按月度拆分为12张表。fee_202001-202012。当查询条件出现月度(tran_month)时,把select语句中的逻辑表名修改为对应的月份表。对query update方法进行拦截在接口上添加注解,通过反射获取接口注解,根据注解上配置的参数进行分表,修改原SQL,例如id取模,按月分表
数据脱敏手机号和身份证在数据库完整存储。但是返回给用户,屏蔽手机号的中间四位。屏蔽身份证号中的出生日期。query——对结果集脱敏
菜单权限控制不同的用户登录,查询菜单权限表时获得不同的结果,在前端展示不同的菜单对query方法进行拦截在方法上添加注解,根据权限配置,以及用户登录信息,在SQL上加上权限过滤条件
黑白名单有些SQL语句在生产环境中是不允许执行的,比如like %%对Executor的update和query方法进行拦截,将拦截的SQL语句和黑白名单 进行比较,控制SQL语句的执行
全局唯一ID在高并发的环境下传统的生成ID的方式不太适用,这时我们就需要考虑其他方式了创建插件拦截Executor的insert方法,通过UUID或者雪花算法来生成ID,并修改SQL中的插入信息

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

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

相关文章

全球化2.0 | ZStack举办香港Partner Day,推动AIOS智塔+DeepSeek海外实践

2025年3月21日&#xff0c;云轴科技ZStack在香港成功举办了主题为“ZStack AIOS 智塔与 DeepSeek 私有化方案介绍及企业应用落地实践”的 Partner Day 活动。此次活动吸引了众多海外合作伙伴&#xff0c;共同探讨 AI Infra 平台在企业私有化 AI 中的应用与价值闭环。 ZStack CT…

【C++初阶】第12课—list

文章目录 1. list的构造2. list迭代器的常见接口2.1 list遍历的迭代器接口2.2 list修改数据的迭代器接口2.3 list排序、逆序、合并相关操作的成员函数 3. 模拟实现list3.1 模拟实现list的构造3.2 模拟实现list的尾插3.3 模拟实现迭代器iterator3.4 模拟实现list的插入删除3.5 模…

谷粒微服务高级篇学习笔记整理---异步线程池

多线程回顾 多线程实现的4种方式 1. 继承 Thread 类 通过继承 Thread 类并重写 run() 方法实现多线程。 public class MyThread extends Thread {Overridepublic void run() {System.out.println("线程运行: " Thread.currentThread().getName());} }// 使用 pub…

Windows学习笔记(4)关于MITRE

基本术语 APT&#xff08;威胁组&#xff0c;高级持续威胁&#xff09; TTP&#xff08;攻击目的技术过程&#xff0c;战术技术和程序&#xff09; ATT&CK框架 网站 https://attack.mitre.org/ CAR知识库 MITRE Engage MITRE D3FEND 网址 https://d3fend.mitre.org/

Share01-WinCC文件越用越大?

为什么你们的经典WinCC项目在客户电脑上运行的越来越慢&#xff1f;为什么查询一个历史曲线慢的要死&#xff1f;为什么重启一下电脑画面都要怀疑人生&#xff1f;具体原因可能多种多样&#xff0c;但是极大可能是您的数据管理设置欠佳&#xff0c;那么闲话少叙&#xff0c;和小…

基于改进粒子群算法的多目标分布式电源选址定容规划(附带Matlab代码)

通过分析分布式电源对配电网的影响&#xff0c;以有功功率损耗、电压质量及分布式电源总容量为优化目标&#xff0c;基于模糊理论建立了分布式电源在配电网中选址定容的多目标优化模型&#xff0c;并提出了一种改进粒子群算法进行求解。在算例仿真中&#xff0c;基于IEEE-14标准…

雨云云应用测评!内测持续进行中!

大家好&#xff0c;时隔一个月&#xff0c;我们又见面了&#xff01; 最近&#xff0c;雨云推出了新型云应用&#xff08;RCA&#xff0c;Rainyun Cloud Application&#xff09;。 通过云应用&#xff0c;你可以快速创建可以外部访问的应用&#xff0c;采用全新的面板和dock…

【算法day25】 最长有效括号——给你一个只包含 ‘(‘ 和 ‘)‘ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

32. 最长有效括号 给你一个只包含 ‘(’ 和 ‘)’ 的字符串&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号子串的长度。 https://leetcode.cn/problems/longest-valid-parentheses/ 2.方法二&#xff1a;栈 class Solution { public:int longestValid…

C++编程学习笔记:函数相关特性、引用与编译流程

目录 一、函数的缺省参数 &#xff08;一&#xff09;全缺省参数 &#xff08;二&#xff09;半缺省参数 二、函数重载 &#xff08;一&#xff09;参数类型不同 &#xff08;二&#xff09;参数个数不同 &#xff08;三&#xff09;参数类型顺序不同 三、引用相关问题…

RPCGC阅读

24年的MM 创新 现有点云压缩工作主要集中在保真度优化上。 而在实际应用中&#xff0c;压缩的目的是促进机器分析。例如&#xff0c;在自动驾驶中&#xff0c;有损压缩会显着丢失户外场景的详细信息。在三维重建中&#xff0c;压缩过程也会导致场景数据中语义信息(Contour)的…

645.错误的集合

import java.util.HashMap; import java.util.Map;/*** program: Test* description: 645 错误的集合* author: gyf* create: 2025-03-23 10:22**/ public class Test {public static void main(String[] args) {}public static int[] findErrorNums(int[] nums) {int[] arr n…

一周学会Flask3 Python Web开发-SQLAlchemy数据迁移migrate

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 模型类(表)不是一成不变的&#xff0c;当你添加了新的模型类&#xff0c;或是在模型类中添加了新的字段&#xff0c;甚至是修改…

Python练习之抽奖界面

前言 一、代码整体架构分析 1、数据层 (Model) 2、控制层 (Controller) 3、视图层 (View) 二、核心功能实现详解 1、 文件导入功能 1.1、实现逻辑 1.2、代码涉及知识点讲解 1.2.1、wildcard 1.2.2、wx.FileDialog 1.2.3、dlg.ShowModal() 2、抽奖动画控制 1.1、…

【云原生】docker 搭建单机PostgreSQL操作详解

目录 一、前言 二、前置准备 2.1 服务器环境 2.2 docker环境 三、docker安装PostgreSQL过程 3.1 获取PostgreSQL镜像 3.2 启动容器 3.2.1 创建数据卷目录 3.2.2 启动pg容器 3.3 客户端测试连接数据库 四、创建数据库与授权 4.1 进入PG容器 4.2 PG常用操作命令 4.2…

算法为舟 思想为楫:AI时代,创作何为?

在科技浪潮汹涌澎湃的当下,AI技术以前所未有的态势席卷各个领域,创作领域亦未能幸免。当生成式AI展现出在剧本撰写、诗歌创作、图像设计等方面的惊人能力时,人类创作者仿佛置身于文明演化的十字路口,迷茫与困惑交织,兴奋与担忧并存。在AI时代,创作究竟该何去何从?这不仅…

JAVA的内存图理解

目录 一、方法区1、类常量池2、静态常量池3、方法区过程 二、栈三、堆1、字符常量池2、堆内存图的绘制 java中内存可以分为 方法区、 堆、 栈、 程序计数器、 本地方法栈&#xff0c;其中比较中重要的是方法区、堆、栈。 一、方法区 1.方法区&#xff08;Method Area&…

医疗CMS高效管理:简化更新维护流程

内容概要 医疗行业内容管理系统&#xff08;CMS&#xff09;的核心价值在于应对医疗信息管理的多维复杂性。面对诊疗指南的动态更新、科研数据的快速迭代以及多机构协作需求&#xff0c;传统管理模式往往面临效率瓶颈与合规风险。现代化医疗CMS通过构建结构化权限管理矩阵&…

低功耗LPWAN模块开发指南:远距离无线通信与边缘计算融合实战‌

在远程资产追踪、野外环境监测等场景中&#xff0c;稳定可靠的长距离通信与超低功耗是系统设计的核心挑战。eFish-SBC-RK3576通过 ‌原生双UART接口 USB OTG扩展能力‌ &#xff0c;可无缝集成主流LPWAN模组&#xff08;LoRa/NB-IoT&#xff09;&#xff0c;实现“数据采集-边…

迅为iTOP-RK3576人工智能开发板Android 系统接口功能测试

2.1 开机启动 开发板接通电源&#xff0c;并按下电源开关&#xff0c;系统即启动&#xff0c;在启动过程中&#xff0c;系统会显示下图中的开机画面&#xff0c;它们分别是 Android 系统启动时的 Logo 画面&#xff1a; 最后会显示如下解锁画面&#xff1a; 2.2 命令终端 将…

RAG基建之PDF解析的“无OCR”魔法之旅

PDF文件转换成其他格式常常是个大难题,大量的信息被锁在PDF里,AI应用无法直接访问。如果能把PDF文件或其对应的图像转换成结构化或半结构化的机器可读格式,那就能大大缓解这个问题,同时也能显著增强人工智能应用的知识库。 嘿,各位AI探险家们!今天我们将踏上了一段奇妙的…