日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

作者:小傅哥
博客:https://bugstack.cn

 

沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!
一、前言

 

片面了!

一月三舟,托爾斯泰說(shuō):“多么偉大的作家,也不過(guò)就是在書(shū)寫(xiě)自己的片面而已”。何況是我,何況是我們!

雖然我們不書(shū)寫(xiě)文章,但我們寫(xiě)需求、寫(xiě)代碼、寫(xiě)注釋,當(dāng)我們遇到了需要被討論的問(wèn)題點(diǎn)時(shí),往往變成了爭(zhēng)論點(diǎn)。這個(gè)好、那個(gè)差、你用的都是啥啥啥!

當(dāng)你把路走窄了,你所能接受到的新的思路、新的想法、新的視野,以及非常重要的收入,也都會(huì)隨之減少。只有橫向?qū)Ρ取⒖冀梃b、查漏補(bǔ)缺,才能讓你的頭腦中會(huì)有更多的思路,無(wú)論是在寫(xiě)代碼上、還是在理財(cái)上、還是在生活上。

二、需求目的

你是否有在使用 IntelliJ IDEA 做開(kāi)發(fā)的過(guò)程,需要拿到執(zhí)行 SQL 語(yǔ)句,復(fù)制出來(lái)做驗(yàn)證的時(shí)候,總是這樣的語(yǔ)句:SELECT * FROM USER WHERE id = ? AND name = ? 又需要自己把 ? 號(hào) 替換成入?yún)⒅的兀?/p>

當(dāng)然這個(gè)需求其實(shí)并不大,甚至你還可以使用其他方式解決。那么在本章節(jié)會(huì)給你提供一個(gè)新的思路,可能你幾乎是沒(méi)過(guò)的方式進(jìn)行處理。

那么在這個(gè)章節(jié)的案例中我們用到基于 IDEA Plugin 開(kāi)發(fā)能力,把字節(jié)碼插樁探針,基于 JAVAagent 的能力,注入到代碼中。再通過(guò)增強(qiáng)后的字節(jié)碼,獲取到 com.MySQL.jdbc.Preparedstatement -> executeInternal 執(zhí)行時(shí)的對(duì)象,從而拿到可以直接測(cè)試的 SQL 語(yǔ)句。

三、案例開(kāi)發(fā) 1. 工程結(jié)構(gòu) guide-idea-plugin-probe ├── .gradle ├── probe-agent │ ├── src │ │ └── main │ │ └── java │ │ └── cn.bugstack.guide.IDEA.plugin │ │ ├── MonitorMethod.java │ │ └── PreAgent.java │ └── build.gradle └── probe-plugin │ └── src │ │ └── main │ │ ├── Java │ │ │ └── cn.bugstack.guide.idea.plugin │ │ │ └── utils │ │ │ │ └── PluginUtil.java │ │ │ └── PerRun.java │ │ └── resources │ │ └── META-INF │ │ └── plugin.xml │ └── build.gradle ├── build.gradle └── gradle.properties

公眾號(hào):bugstack蟲(chóng)洞棧 回復(fù):idea 即可下載全部 IDEA 插件開(kāi)發(fā)源碼

在此 IDEA 插件工程中,工程結(jié)構(gòu)分為2塊:

 

  • probe-agent:探針模塊,用于編譯打包提供字節(jié)碼增強(qiáng)服務(wù),給 probe-plugin 模塊使用
  • probe-plugin:插件模塊,通過(guò) java.programPatcher 加載字節(jié)碼增強(qiáng)包,獲取并打印執(zhí)行數(shù)據(jù)庫(kù)操作的 SQL 語(yǔ)句。
2. 字節(jié)碼增強(qiáng)獲取 SQL

 

此處的字節(jié)碼增強(qiáng)方式,采用的 Byte-Buddy 字節(jié)碼框架,它的使用方式更加簡(jiǎn)單,在使用的過(guò)程中有些像使用 AOP 的攔截方式一樣,獲取到你需要的信息。

此外在 gradle 打包構(gòu)建的時(shí)候,需要添加 shadowJar 模塊,把 Premain-Class 打包進(jìn)去。這部分代碼中可以查看

2.1 探針入口

cn.bugstack.guide.idea.plugin.PreAgent

//JVM 首先嘗試在代理類上調(diào)用以下方法 public static void premain(String agentArgs, Instrumentation inst) { AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> { return builder .method(ElementMatchers.named("executeInternal")) // 攔截任意方法 .intercept(MethodDelegation.to(MonitorMethod.class)); // 委托 }; new AgentBuilder .Default() .type(ElementMatchers.nameStartsWith("com.mysql.jdbc.PreparedStatement")) .transform(transformer) .installOn(inst); }

  • 通過(guò) Byte-buddy 配置,攔截匹配的類和方法,因?yàn)檫@個(gè)類和方法下,可以獲取到完整的執(zhí)行 SQL 語(yǔ)句。
2.2 攔截 SQL

 

cn.bugstack.guide.idea.plugin.MonitorMethod

@RuntimeType public static Object intercept(@This Object obj, @Origin Method method, @SuperCall Callable callable, @AllArguments Object... args) throws Exception { try { return callable.call(); } finally { String originalSql = (String) BeanUtil.getFieldValue(obj, "originalSql"); String replaceSql = ReflectUtil.invoke(obj, "asSql"); System.out.println("數(shù)據(jù)庫(kù)名稱:mysql"); System.out.println("線程ID:" + Thread.currentThread().getId()); System.out.println("時(shí)間:" + new Date()); System.out.println("原始SQL:rn" + originalSql); System.out.println("替換SQL:rn" + replaceSql); } }

  • 攔截方法入?yún)⑹且环N可配置操作,比如 @This Object obj 是為了獲取當(dāng)前類的執(zhí)行對(duì)象,@Origin Method method 是為了獲取執(zhí)行方法。
  • 在 finally 塊中,我們可以通過(guò)反射拿到當(dāng)前類的屬性信息,以及反射拿到執(zhí)行的 SQL,并做打印輸出。
2.3 編譯打包

 

在測(cè)試和開(kāi)發(fā) IDEA Plugin 插件之前,我們需要先進(jìn)行一個(gè)打包操作,這個(gè)打包就是把字節(jié)碼增強(qiáng)的代碼打包整一個(gè) Jar 包。在 build.gradle -> shadowJar


 

 

  • 打包編譯后,就可以在 build -> libs 下看到 jar:probe-agent-1.0-SNAPSHOT-all.jar 這個(gè) Jar 就是用來(lái)做字節(jié)碼增強(qiáng)處理的。
2.4 測(cè)試驗(yàn)證

 

這里在把寫(xiě)好的字節(jié)碼增強(qiáng)組件給插件使用之前,可以做一個(gè)測(cè)試驗(yàn)證,避免每次都需要啟動(dòng)插件才能做測(cè)試。

單元測(cè)試

public class ApiTest { public static void main(String[] args) throws Exception { String URL = "jdbc:mysql://127.0.0.1:3306/itstack?characterEncoding=utf-8"; String USER = "root"; String PASSword = "123456"; Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); String sql="SELECT * FROM USER WHERE id = ? AND name = ?"; PreparedStatement statement = conn.prepareStatement(sql); statement.setLong(1,1L); statement.setString(2,"謝飛機(jī)"); ResultSet rs = statement.executeQuery(); while (rs.next()) { System.out.println(rs.getString("name") + " " + rs.getString("address")); } } }

  • VM options:-javaagent:你的路徑libsprobe-agent-1.0-SNAPSHOT-all.jar
  • 注意在測(cè)試運(yùn)行的時(shí)候,你要給 ApiTest 配置 VM options 才能打印攔截 SQL 信息

 

測(cè)試結(jié)果

原始SQL: SELECT * FROM USER WHERE id = ? AND name = ? 替換SQL: SELECT * FROM USER WHERE id = 1 AND name = '謝飛機(jī)' 謝飛機(jī) 北京.大興區(qū).通明湖公園

  • 好啦,這樣我們就可以攔截可以復(fù)制執(zhí)行的 SQL 語(yǔ)句了,接下來(lái)我們?cè)僮鱿?IDEA Plugin 的處理。
3. 通過(guò)插件開(kāi)發(fā)引入探針 Jar

 

接下來(lái)我們要把開(kāi)發(fā)好的字節(jié)碼增強(qiáng) Jar 包,復(fù)制到 IDEA Plugin 插件開(kāi)發(fā)模塊中的 libs(可自己創(chuàng)建) 下,之后在 plugin.xml 配置加載 implementation fileTree(dir: 'libs', includes: ['*jar']) 這樣就可以程序中,找到這個(gè) jar 包并配置到程序中。

3.1 復(fù)制 jar 到 libs 下


 

3.2 build.gradle 配置加載 dependencies { implementation fileTree(dir: 'libs', includes: ['*jar']) }

  • 通過(guò) implementation fileTree 引入加載文件樹(shù)的方式,把我們配置好的 Jar 加載到程序運(yùn)行中。
3.3 程序中引入 javaagent

 

cn.bugstack.guide.idea.plugin.PerRun

public class PerRun extends JavaProgramPatcher { @Override public void patchJavaParameters(Executor executor, RunProfile configuration, JavaParameters javaParameters) { RunConfiguration runconfiguration = (RunConfiguration) configuration; ParametersList vmParametersList = javaParameters.getVMParametersList(); vmParametersList.addParametersString("-javaagent:" + agentCoreJarPath); vmParametersList.addNotEmptyProperty("guide-idea-plugin-probe.projectId", runConfiguration.getProject().getLocationHash()); } }

  • 通過(guò)繼承 JavaProgramPatcher 類,實(shí)現(xiàn) patchJavaParameters 方法,通過(guò) configuration 屬性來(lái)配置我們自己需要被加載的 -javaagent 包。
  • 這樣在通過(guò) IDEA 已經(jīng)安裝此插件,運(yùn)行代碼的時(shí)候,就會(huì)執(zhí)行到這個(gè)攔截和打印 SQL 的功能。
3.4 plugin.xml 添加配置
  • 之后你還需要把開(kāi)發(fā)好的加載類,配置到 java.programPatcher 這樣就可以程序運(yùn)行的時(shí)候,被加載到了。
四、測(cè)試驗(yàn)證
  • 準(zhǔn)備好一個(gè)有數(shù)據(jù)庫(kù)操作的工程,需要的是 JDBC,如果是其他的,你需要自己擴(kuò)展
  • 啟動(dòng)插件后,打開(kāi)你的工程,運(yùn)行單元測(cè)試,查看打印區(qū)

 

啟動(dòng)插件


 

 

  • 如果你是新下載代碼,那么可以在 probe-plugin -> Tasks -> intellij -> runIde 中進(jìn)行運(yùn)行啟動(dòng)。

 

單元測(cè)試

@Test public void test_update(){ User user = new User(); user.setId(1L); user.setName("謝飛機(jī)"); user.setAge(18); user.setAddress("北京.大興區(qū).亦莊經(jīng)濟(jì)開(kāi)發(fā)區(qū)"); userDao.update(user); }

測(cè)試結(jié)果

22:30:55.593 [main] DEBUG cn.bugstack.test.demo.infrastructure.dao.UserDao.update[143] - ==> Preparing: UPDATE user SET name=?,age=?,address=? WHERE id=? 22:30:55.625 [main] DEBUG cn.bugstack.test.demo.infrastructure.dao.UserDao.update[143] - ==> Parameters: 謝飛機(jī)(String), 18(Integer), 北京.大興區(qū).亦莊經(jīng)濟(jì)開(kāi)發(fā)區(qū)(String), 1(Long) 數(shù)據(jù)庫(kù)名稱:Mysql 線程ID:1 原始SQL: UPDATE user SET name=?,age=?,address=? WHERE id=? 替換SQL: UPDATE user SET name='謝飛機(jī)',age=18,address='北京.大興區(qū).亦莊經(jīng)濟(jì)開(kāi)發(fā)區(qū)' WHERE id=1

  • 通過(guò)測(cè)試結(jié)果可以看到,我們可以獲取到直接拿去測(cè)試驗(yàn)證的 SQL 語(yǔ)句了,就不用在復(fù)制帶問(wèn)號(hào)的 SQL 還得修改后測(cè)試了。
五、總結(jié)
  • 首先我們是在本章節(jié)初步嘗試使用多模塊的方式來(lái)創(chuàng)建工程,這樣的方式可以更加好維護(hù)各類一個(gè)工程下所需要的代碼模塊。你也可以嘗試使用 gradle 創(chuàng)建多模塊工程
  • 對(duì)于字節(jié)碼插樁增強(qiáng)的使用方式,本篇只是一個(gè)介紹,這項(xiàng)技術(shù)還可以運(yùn)用到更多的場(chǎng)景,開(kāi)發(fā)出各種提升研發(fā)效率的工具。
  • 了解額外的 Jar 包是怎么加載到工程的,以及如何通過(guò)配置的方式讓 javaagent 引入自己開(kāi)發(fā)好的探針組件。

分享到:
標(biāo)簽:SQL
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定