欢迎光临
我们一直在努力

【12.MyBatis源码剖析与架构实战】MyBatis与设计模式-4.代理模式

MyBatis 与代理模式(Proxy Pattern)详解

代理模式是一种结构型设计模式,它为另一个对象提供一个替身(代理)以控制对这个对象的访问。在 MyBatis 中,代理模式被广泛应用于 Mapper 接口的动态代理 和 延迟加载 两大核心特性,同时插件机制也基于动态代理实现拦截。


一、代理模式概述

意图:为其他对象提供一种代理以控制对这个对象的访问。

参与者:

  • Subject:抽象主题,声明真实对象和代理对象的共同接口。
  • RealSubject:真实主题,定义真正的业务逻辑。
  • Proxy:代理,持有对 RealSubject 的引用,并在调用前后执行附加操作。

分类:

  • 静态代理:在编译时确定代理类。
  • 动态代理:运行时动态生成代理类(JDK 动态代理或 CGLIB)。

MyBatis 主要使用 JDK 动态代理(Mapper 接口、延迟加载代理、插件拦截链)和 CGLIB(某些延迟加载场景)。


二、MyBatis 中代理模式的典型应用

应用场景
代理对象(Proxy)
真实对象(RealSubject)
实现技术
Mapper 接口调用 MapperProxy SqlSession 的数据库操作 JDK 动态代理
延迟加载(关联对象) 由 ProxyFactory 生成的代理 目标实体对象 Javassist / CGLIB
插件(Interceptor) 由 Plugin 生成的代理 Executor, StatementHandler 等 JDK 动态代理

下面重点剖析 Mapper 接口动态代理 和 延迟加载代理。


三、Mapper 接口的动态代理(MapperProxy)

MyBatis 允许开发者只定义 Mapper 接口(如 UserMapper)而不需要编写实现类,调用接口方法时会自动执行对应的 SQL。这完全依赖动态代理。

3.1 UML 类图

#mermaid-svg-EVTSpDO3B94t1o6k{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EVTSpDO3B94t1o6k .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EVTSpDO3B94t1o6k .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EVTSpDO3B94t1o6k .error-icon{fill:#552222;}#mermaid-svg-EVTSpDO3B94t1o6k .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EVTSpDO3B94t1o6k .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EVTSpDO3B94t1o6k .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EVTSpDO3B94t1o6k .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EVTSpDO3B94t1o6k .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EVTSpDO3B94t1o6k .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EVTSpDO3B94t1o6k .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EVTSpDO3B94t1o6k .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EVTSpDO3B94t1o6k .marker.cross{stroke:#333333;}#mermaid-svg-EVTSpDO3B94t1o6k svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EVTSpDO3B94t1o6k p{margin:0;}#mermaid-svg-EVTSpDO3B94t1o6k g.classGroup text{fill:#9370DB;stroke:none;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-EVTSpDO3B94t1o6k g.classGroup text .title{font-weight:bolder;}#mermaid-svg-EVTSpDO3B94t1o6k .cluster-label text{fill:#333;}#mermaid-svg-EVTSpDO3B94t1o6k .cluster-label span{color:#333;}#mermaid-svg-EVTSpDO3B94t1o6k .cluster-label span p{background-color:transparent;}#mermaid-svg-EVTSpDO3B94t1o6k .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EVTSpDO3B94t1o6k .cluster text{fill:#333;}#mermaid-svg-EVTSpDO3B94t1o6k .cluster span{color:#333;}#mermaid-svg-EVTSpDO3B94t1o6k .nodeLabel,#mermaid-svg-EVTSpDO3B94t1o6k .edgeLabel{color:#131300;}#mermaid-svg-EVTSpDO3B94t1o6k .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-EVTSpDO3B94t1o6k .label text{fill:#131300;}#mermaid-svg-EVTSpDO3B94t1o6k .labelBkg{background:#ECECFF;}#mermaid-svg-EVTSpDO3B94t1o6k .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-EVTSpDO3B94t1o6k .classTitle{font-weight:bolder;}#mermaid-svg-EVTSpDO3B94t1o6k .node rect,#mermaid-svg-EVTSpDO3B94t1o6k .node circle,#mermaid-svg-EVTSpDO3B94t1o6k .node ellipse,#mermaid-svg-EVTSpDO3B94t1o6k .node polygon,#mermaid-svg-EVTSpDO3B94t1o6k .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EVTSpDO3B94t1o6k .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k g.clickable{cursor:pointer;}#mermaid-svg-EVTSpDO3B94t1o6k g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-EVTSpDO3B94t1o6k g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-EVTSpDO3B94t1o6k .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-EVTSpDO3B94t1o6k .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-EVTSpDO3B94t1o6k .dashed-line{stroke-dasharray:3;}#mermaid-svg-EVTSpDO3B94t1o6k .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-EVTSpDO3B94t1o6k #compositionStart,#mermaid-svg-EVTSpDO3B94t1o6k .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #compositionEnd,#mermaid-svg-EVTSpDO3B94t1o6k .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #dependencyStart,#mermaid-svg-EVTSpDO3B94t1o6k .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #dependencyStart,#mermaid-svg-EVTSpDO3B94t1o6k .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #extensionStart,#mermaid-svg-EVTSpDO3B94t1o6k .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #extensionEnd,#mermaid-svg-EVTSpDO3B94t1o6k .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #aggregationStart,#mermaid-svg-EVTSpDO3B94t1o6k .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #aggregationEnd,#mermaid-svg-EVTSpDO3B94t1o6k .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #lollipopStart,#mermaid-svg-EVTSpDO3B94t1o6k .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k #lollipopEnd,#mermaid-svg-EVTSpDO3B94t1o6k .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-EVTSpDO3B94t1o6k .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-EVTSpDO3B94t1o6k .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EVTSpDO3B94t1o6k .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EVTSpDO3B94t1o6k .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EVTSpDO3B94t1o6k :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

实现

InvocationHandler

创建

委托

持有

«interface»

UserMapper

+selectById(Long id) : User

+insert(User user) : int

MapperProxy<T>

-SqlSession sqlSession

-Class<T> mapperInterface

-Map<Method, MapperMethod> methodCache

+invoke(Object proxy, Method method, Object[] args) : Object

MapperProxyFactory<T>

-Class<T> mapperInterface

-Map<Method, MapperMethod> methodCache

+newInstance(SqlSession sqlSession) : T

-newInstance(MapperProxy<T> mapperProxy) : T

«interface»

SqlSession

+selectOne(String statement, Object parameter)

+insert(String statement, Object parameter)

+getMapper(Class<T> type) : T

赞(0)
未经允许不得转载:171主机测评 » 【12.MyBatis源码剖析与架构实战】MyBatis与设计模式-4.代理模式
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址