国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

超全MyBatis動態代理詳解!

開發 前端
眾所周知哈,Mybatis 底層封裝使用的 JDK 動態代理。說 Mybatis 動態代理之前,先來看一下平常我們寫的動態代理 Demo,拋磚引玉.

[[375755]]

本文轉載自微信公眾號「源碼興趣圈」,作者龍臺  。轉載本文請聯系源碼興趣圈公眾號。 

前言

假如有人問你這么幾個問題,看能不能答上來

  1. Mybatis Mapper 接口沒有實現類,怎么實現的動態代理
  2. JDK 動態代理為什么不能對類進行代理(充話費送的問題)
  3. 抽象類可不可以進行 JDK 動態代理(附加問題)

答不上來的鐵汁,證明 Proxy、Mybatis 源碼還沒看到位。不過沒有關系,繼續往下看就明白了

動態代理實戰

眾所周知哈,Mybatis 底層封裝使用的 JDK 動態代理。說 Mybatis 動態代理之前,先來看一下平常我們寫的動態代理 Demo,拋磚引玉

一般來說定義 JDK 動態代理分為三個步驟,如下所示

  1. 定義代理接口
  2. 定義代理接口實現類
  3. 定義動態代理調用處理器

三步代碼如下所示,玩過動態代理的小伙伴看過就能明白

  1. public interface Subject { // 定義代理接口 
  2.     String sayHello(); 
  3.  
  4. public class SubjectImpl implements Subject {  // 定義代理接口實現類 
  5.     @Override 
  6.     public String sayHello() { 
  7.         System.out.println(" Hello World"); 
  8.         return "success"
  9.     } 
  10.  
  11. public class ProxyInvocationHandler implements InvocationHandler {  // 定義動態代理調用處理器 
  12.     private Object target; 
  13.  
  14.     public ProxyInvocationHandler(Object target) { 
  15.         this.target = target; 
  16.     } 
  17.  
  18.     @Override 
  19.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  20.         System.out.println(" 🧱 🧱 🧱 進入代理調用處理器 "); 
  21.         return method.invoke(target, args); 
  22.     } 

1.寫個測試程序,運行一下看看效果,同樣是分三步

2.創建被代理接口的實現類

  • 創建動態代理類,說一下三個參數
  • 類加載器
  • 被代理類所實現的接口數組

3.用處理器(調用被代理類方法,每次都經過它)

被代理實現類調用方法

  1. public class ProxyTest { 
  2.     public static void main(String[] args) { 
  3.         Subject subject = new SubjectImpl(); 
  4.         Subject proxy = (Subject) Proxy 
  5.                 .newProxyInstance( 
  6.                         subject.getClass().getClassLoader(), 
  7.                         subject.getClass().getInterfaces(), 
  8.                         new ProxyInvocationHandler(subject)); 
  9.  
  10.         proxy.sayHello(); 
  11.         /** 
  12.          * 打印輸出如下 
  13.          * 調用處理器:🧱 🧱 🧱 進入代理調用處理器 
  14.          * 被代理實現類:Hello World 
  15.          */ 
  16.     } 

Demo 功能實現了,大致運行流程也清楚了,下面要針對原理實現展開分析

動態代理原理分析

從原理的角度上解析一下,上面動態代理測試程序是如何執行的

第一步簡單明了,創建了 Subject 接口的實現類,也是我們常規的實現

第二步是創建被代理對象的動態代理對象。這里有朋友就問了,怎么證明這是個動態代理對象?如圖所示

JDK 動態代理對象名稱是有規則的,凡是經過 Proxy 類生成的動態代理對象,前綴必然是 $Proxy,后面的數字也是名稱組成部分

如果有小伙伴想要一探究竟,關注 Proxy 內部類 ProxyClassFactory,這里會有想要的答案

回歸正題,繼續看一下 ProxyInvocationHandler,內部保持了被代理接口實現類的引用,invoke 方法內部使用反射調用被代理接口實現類方法

可以看出生成的動態代理類,繼承了 Proxy 類,然后對 Subject 接口進行了實現,而實現方法 sayHello 中實際調用的是 ProxyInvocationHandler 的 invoke 方法

一不小心發現了 JDK 動態代理不能對類進行代理的原因 ^ ^

也就是說,當我們調用 Subject#sayHello 時,方法調用鏈是這樣的

但是,Demo 里有被代理接口的實現類,Mybatis Mapper 沒有,這要怎么玩

不知道不要緊,知道了估計也看不到這了,一起看下 mybatis 源碼是怎么玩的

mybatis version:3.4.x

Mybatis 源碼實現

不知道大家考沒考慮過這么一個問題,Mybatis Mapper 為什么不需要實現類?

假如說,我們項目使用的三層設計,Controller 控制請求接收,Service 負責業務處理,Mapper 負責數據庫交互

Mapper 層也就是我們常說的數據庫映射層,負責對數據庫的操作,比如對數據的查詢或者新增、刪除等

大膽設想下,項目沒有使用 Mybatis,需要在 Mapper 實現層寫數據庫交互,會寫一些什么內容?

會寫一些常規的 JDBC 操作,比如:

  1. // 裝載Mysql驅動 
  2. Class.forName(driveName); 
  3. // 獲取連接 
  4. con = DriverManager.getConnection(url, user, pass); 
  5. // 創建Statement 
  6. Statement state = con.createStatement(); 
  7. // 構建SQL語句 
  8. String stuQuerySqlStr = "SELECT * FROM STUDENT"
  9. // 執行SQL返回結果 
  10. ResultSet result = state.executeQuery(stuQuerySqlStr); 
  11. ... 

如果項目中所有 Mapper 實現層都要這么玩,那豈不是很想打人...

所以 Mybatis 結合項目痛點,應運而生,怎么做的呢

將所有和 JDBC 交互的操作,底層采用 JDK 動態代理封裝,使用者只需要自定義 Mapper 和 .xml 文件

SQL 語句定義在 .xml 文件或者 Mapper 中,項目啟動時通過解析器解析 SQL 語句組裝為 Java 中的對象

解析器分為多種,因為 Mybatis 中不僅有靜態語句,同時也包含動態 SQL 語句

這也就是為什么 Mapper 接口不需要實現類,因為都已經被 Mybatis 通過動態代理封裝了,如果每個 Mapper 都來一個實現類,臃腫且無用。經過這一頓操作,展示給我們的就是項目里用到的 Mybatis 框架

上面鋪墊這么久,終于要到主角了,為什么 Mybatis Mapper 接口沒有實現類也可以實現動態代理

想要嚴格按照先后順序介紹 Mybatis 動態代理流程,而不超前引用未介紹過的術語,這幾乎是不可能的,筆者盡量說的通俗易懂

無實現類完成動態代理

核心點來了,拿起小本本坐板正了

我們先來看下普通動態代理有沒有可能不用實現類,僅靠接口完成

  1. public interface Subject { 
  2.     String sayHello(); 
  3.  
  4. public class ProxyInvocationHandler implements InvocationHandler { 
  5.  
  6.     @Override 
  7.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  8.         System.out.println(" 🧱 🧱 🧱 進入代理調用處理器 "); 
  9.         return "success"
  10.     } 

根據代碼可以看到,我們并沒有實現接口 Subject,繼續看一下怎么實現動態代理

  1. public class ProxyTest { 
  2.     public static void main(String[] args) { 
  3.         Subject proxy = (Subject) Proxy 
  4.                 .newProxyInstance( 
  5.                         subject.getClass().getClassLoader(), 
  6.                         new Class[]{Subject.class}, 
  7.                         new ProxyInvocationHandler()); 
  8.  
  9.         proxy.sayHello(); 
  10.         /** 
  11.          * 打印輸出如下 
  12.          * 調用處理器:🧱 🧱 🧱 進入代理調用處理器 
  13.          */ 
  14.     } 

可以看到,對比文初的 Demo,這里對 Proxy.newProxyInstance 方法的參數作出了變化

之前是通過實現類獲取所實現接口的 Class 數組,而這里是把接口本身放到 Class 數組中,殊歸同途

有實現類接口和無實現類接口產生的動態代理類有什么區別

  1. 有實現類接口是對 InvocationHandler#invoke 方法調用,invoke 方法通過反射調用被代理對象(SubjectImpl)方法(sayHello)
  2. 無實現類接口則是僅對 InvocationHandler#invoke 產生調用。所以有實現類接口返回的是被代理對象接口返回值,而無實現類接口返回的僅是 invoke 方法返回值

InvocationHandler#invoke 方法返回值是 success 字符串,定義個字符串變量,是否能成功返回

現在第一個問題答案已經浮現,Mapper 沒有實現類,所有調用 JDBC 等操作都是在 Mybatis InvocationHandler 實現的

問題既然已經得到了解決,給人一種感覺,好像沒那么難,但是你不好奇,Mybatis 底層怎么做的么?

先拋出一個問題,然后帶著問題去看源碼,可能讓你記憶 Double 倍深刻

咱們 Demo 里的接口是固定的,Mybatis Mapper 可是不固定的,怎么搞?

Mybatis 是這么說的

看看 Mybatis 底層它怎么實現的動態接口代理,小伙伴只需要關注標記處的代碼即可

和我們的 Demo 代碼很像,核心點在于 mapperInterface 它是怎么賦值的

先來說一下 Mybatis 代理工廠中具體生成動態代理類具體邏輯

  1. 根據 .xml 上關聯的 namespace, 通過 Class#forName 反射的方式返回 Class 對象(不止 .xml namespace 一種方式)
  2. 將得到的 Class 對象(實際就是接口對象)傳遞給 Mybatis 代理工廠生成代理對象,也就是剛才 mapperInterface 屬性

謎底揭曉,Mybatis 使用接口全限定名通過 Class#forName 生成 Class 對象,這個 Class 對象類型就是接口

為了方便大家理解,通過 Mybatis 源碼提供的測試類舉例。假設已有接口 AutoConstructorMapper 以及對應的 .xml 如下

執行第一步,根據 .xml namespace 得到 Class 對象

首先第一步獲取 .xml 上 mapper 標簽 namespace 屬性,得到 mapper 接口全限定信息

根據 mapper 全限定信息獲取 Class 對象

添加到對應的映射器容器中,等待生成動態代理對象

如果此時調用生成動態代理對象,代理工廠 newInstance 方法如下:

至此,文初提的 Proxy、Mybatis 動態代理相關問題已全部答疑

抽象類能否 JDK 動態代理

說代碼前結論先行,不能!

  1. public abstract class AbstractProxy { 
  2.     abstract void sayHello(); 
  3.  
  4. AbstractProxy proxyInterface = (AbstractProxy) Proxy 
  5.         .newProxyInstance( 
  6.                 ProxyTest.class.getClassLoader(), 
  7.                 new Class[]{AbstractProxy.class}, 
  8.                 new ProxyInvocationHandler()); 
  9. proxyInterface.sayHello(); 

毫無疑問,報錯是必然的,JDK 是不能對類進行代理的

帶著小疑惑我們看一下 Proxy 源碼報錯位置,JDK 動態代理在生成代理類的過程代碼中,會有是否接口驗證

抽象類終歸是類,加個 abstract 也成不了接口(就像我,雖然胖了 60 斤,但依然是帥哥)

下次面試官如果有問這問題的,斬釘截鐵一點,就是不能

結言

結合 Mybatis 使用 JDK 動態代理相關的問題,展開了文章的講述,這里總結如下

Q:JDK 動態代理能否對類代理?

因為 JDK 動態代理生成的代理類,會繼承 Proxy 類,由于 Java 無法多繼承,所以無法對類進行代理

Q:抽象類是否可以 JDK 動態代理?

不可以,抽象類本質上也是類,Proxy 生成代理類過程中,會校驗傳入 Class 是否接口

Q:Mybatis Mapper 接口沒有實現類,怎么實現的動態代理?

Mybatis 會通過 Class#forname 得到 Mapper 接口 Class 對象,生成對應的動態代理對象,核心業務處理都會在 InvocationHandler#invoke 進行處理

希望讀過的小伙伴都能有所收獲,如果對于文章內容有所疑惑,可以通過留言或者添加作者好友的方式溝通,祝好!

 

責任編輯:武曉燕 來源: 源碼興趣圈
相關推薦

2023-12-06 08:23:44

代理模式設計模式

2021-07-06 06:39:22

Java靜態代理動態代理

2021-03-23 09:52:39

鴻蒙HarmonyOS應用開發

2017-05-11 21:30:01

Android動態代理ServiceHook

2011-04-06 11:41:25

Java動態代理

2011-03-07 17:15:52

ProFTPD配置

2011-03-07 17:25:33

ProFTPD啟動

2011-03-07 17:24:33

ProFTPD安裝

2015-08-26 16:38:37

mybatissql

2012-08-28 10:59:26

JavaJava動態代理Proxy

2025-07-29 07:30:23

Spring動態代理代碼

2015-09-22 11:09:47

Java 8動態代理

2011-03-23 10:40:51

java代理模式

2017-10-12 14:56:11

2022-01-26 00:05:00

AOPRPC遠程調用

2020-12-28 07:47:35

動態代理AOP

2024-11-07 16:39:42

SpringBoo常用注解Bean

2020-12-28 09:41:40

MySQL數據庫函數

2022-09-01 10:40:29

SpringAOPJDK
點贊
收藏

51CTO技術棧公眾號

精品女厕一区二区三区| 欧美精品一区在线播放| 隔壁人妻偷人bd中字| 亚洲国产日韩欧美一区二区三区| 91国产精品视频在线| 黄页免费欧美| 亚洲黄色片网站| 色婷婷视频在线观看| 欧美日韩在线免费视频| 水莓100国产免费av在线播放| 国产精品福利电影一区二区三区四区| 免费一级特黄毛片| 国产盗摄精品一区二区三区在线 | 一区二区欧美日韩视频| 99热国产在线| 91精品国产高清一区二区三区蜜臀| 青青操视频在线| 欧美日韩免费网站| 精品av中文字幕在线毛片| 精品色蜜蜜精品视频在线观看| 激情视频网址| 亚洲一区二区欧美激情| 22288色视频在线观看| 亚洲综合色自拍一区| 米奇.777.com| 亚洲午夜私人影院| 欧美孕妇孕交| 欧美日韩aaaaa| 尤物视频在线看| 亚洲视频欧洲视频| 亚洲专区**| 日本视频久久久| 夜间精品视频| 欧美xxxx黑人又粗又长密月| 国产欧美日本| 看全色黄大色大片| 成人午夜电影小说| 爱情岛论坛亚洲首页入口章节| 亚洲久草在线视频| 成人动漫在线播放| 日韩国产欧美精品一区二区三区| 嫩草伊人久久精品少妇av杨幂| 欧美激情一级欧美精品| 欧美日韩激情| 欧美日韩高清免费| a亚洲天堂av| 日韩日韩日韩日韩| 91精品国产色综合久久不卡电影| 欧美片第1页| 日韩美女写真福利在线观看| 国模 一区 二区 三区| 99久久久无码国产精品性色戒| 99精品久久久久久| 国内福利写真片视频在线 | 日韩欧美一级在线播放| 中文在线免费视频| 欧美精品久久久久久久| 91亚洲一区| 一区二区三区四区欧美日韩| 成人国产在线观看| 蜜桃视频中文字幕| 亚洲成色777777在线观看影院| 免费精品一区二区三区在线观看| 成人做爽爽免费视频| 国产一区二区在线看| www.99色| 精品久久人人做人人爰| 日韩一区网站| 久久久久无码国产精品一区| 久久综合色播五月| 成年人视频免费在线观看| 精品久久国产精品| 精品动漫3d一区二区三区免费版| 国产精品一线二线三线| 一本到高清视频免费精品| 91p九色成人| 99re6在线| 国产精品无人区| 91超碰在线| 成人免费看黄网站| 视频一区视频二区视频三区高| 久久综合亚洲社区| 欧美丰满日韩| 超级碰在线观看| 亚洲激情综合网| 免费在线国产视频| 日本亚洲欧美三级| 老司机精品视频在线| 特黄特色大片免费视频大全| 日韩精品视频在线观看网址| 日韩免费一区| 久色视频在线播放| 欧美精三区欧美精三区| 六月丁香久久丫| 欧美 亚洲 视频| 色视频欧美一区二区三区| av在线国产精品| 日本一区二区久久精品| 亚洲午夜激情网页| 国产美女视频一区二区| 日韩欧美在线电影| 色婷婷亚洲一区二区三区| 国产精品对白久久久久粗| 天天综合五月天| 在线电影国产精品| 99久久夜色精品国产亚洲96| 日本免费观看网站| 国产亚洲精品美女久久久| 欧美日韩一区二区高清| 麻豆福利视频| 久久久久久国产精品三级玉女聊斋 | а√中文在线8| 日韩在线免费看| 国产精选久久久久久| 欧美性欧美巨大黑白大战| 一区二区三区|亚洲午夜| 中文幕一区二区三区久久蜜桃| a级网站在线播放| 国产精品视频内| 最新中文字幕一区二区三区| 日本国产亚洲| 久久天天躁狠狠躁夜夜躁2014 | 97久久人人超碰caoprom| 涩涩视频在线播放| www.亚洲一二| 天海翼精品一区二区三区| 91超碰在线播放| 欧美中文字幕精在线不卡| 美女航空一级毛片在线播放| 久久这里只精品| 国产精品嫩草视频| 欧美性极品少妇| 日韩精品亚洲专区| 免费h视频在线观看| 男人靠女人免费视频网站| 日韩av成人| 99久久婷婷国产综合精品电影√| 黄色激情在线视频| 亚洲午夜国产成人av电影男同| 成人小视频免费在线观看| 欧美日韩精品免费观看视欧美高清免费大片 | 精品欧美不卡一区二区在线观看| 国产精品第100页| 亚洲国产精品自拍| 网红女主播少妇精品视频| 美女av免费在线观看| 欧洲美女免费图片一区| 欧美色区777第一页| 国产不卡高清在线观看视频| 精品久久久中文字幕| 在线免费91| 亚洲看片网站| 国产精品视频免费观看www| 久久中文字幕一区| 亚洲成av人片观看| 尤物视频在线免费观看| 999在线观看免费大全电视剧| 色吊一区二区三区| 久久久久.com| 日韩制服一区| 成人福利视频在| 成人中文字幕在线观看| 4438x成人网最大色成网站| 亚洲精品视频在线免费| 日韩成人综合网| 日本免费精品| 在线观看欧美日韩电影| 日本久久精品一区二区| 亚洲欧洲日韩在线| 欧洲杯什么时候开赛| 阿v免费在线观看| 亚洲一区bb| 九九热精品视频| 天天综合色天天综合色h| 日日嗨av一区二区三区四区| 久久久精品一区二区毛片免费看| 蜜桃视频网站www| 亚洲巨乳在线观看| 57pao国产成人免费| 欧美三片在线视频观看| 国产99久久久精品| 久久精品国产www456c0m| av在线小说| 亚洲xxxx2d动漫1| 久久狠狠久久综合桃花| 精品国偷自产在线视频99| 亚洲综合色噜噜狠狠| 日韩成人一级大片| 久久99国产精品久久99大师| 老司机精品视频在线观看6| 男人靠女人免费视频网站| 国产精品美女诱惑| 欧美激情免费观看| 欧美一区二区三区四区久久| 欧美国产乱子伦 | 自拍偷拍亚洲精品| 欧美日韩国产精品一区二区不卡中文| 国产精品99久久久久久久vr | 国产精品久久久久久久久久99 | 午夜精品一区二区三区av|