【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD布蔗,那這種技術(shù)棧你永遠(yuǎn)碰不到

轉(zhuǎn)自【阿里云云棲號(hào)】

一、前言

寫(xiě)這篇文章的時(shí)候我在想可能大部分程序員包括你我浪腐,常常都在忙于業(yè)務(wù)開(kāi)發(fā)或奔波在日常維護(hù)與修復(fù)BUG的路上纵揍,當(dāng)不能從中吸取技術(shù)營(yíng)養(yǎng)與改變現(xiàn)狀后,就像一臺(tái)恒定運(yùn)行的機(jī)器议街,逃不出限定宇宙速度的一個(gè)圈里泽谨。可能你也會(huì)有自己的難處,平時(shí)加班太晚沒(méi)有時(shí)間學(xué)習(xí)吧雹、周末家里瑣事太多沒(méi)有精力投入骨杂,放假計(jì)劃太滿沒(méi)有空閑安排⌒劬恚總之腊脱,學(xué)習(xí)就會(huì)被擱置。而當(dāng)一年年的過(guò)去后龙亲,當(dāng)自己的年齡與能力不成匹配后又會(huì)后悔沒(méi)有給多投入一些時(shí)間學(xué)習(xí)成長(zhǎng)陕凹。

尤其是一線編碼的技術(shù)人,除了我們所能看到的在技術(shù)框架里(SSM)開(kāi)發(fā)的業(yè)務(wù)代碼鳄炉,你是否有遇到過(guò)學(xué)習(xí)瓶頸杜耙,而這種瓶頸又是你自己不知道自己不會(huì)什么,就像下面這些技術(shù)列表里拂盯,你有了解多少佑女;

  1. javaagent
  2. asm
  3. jvmti
  4. javaassit
  5. netty
  6. 算法,搜索引擎
  7. cglib
  8. 混沌工程
  9. 中間件開(kāi)發(fā)
  10. 高級(jí)測(cè)試谈竿;壓力測(cè)試团驱、鏈路測(cè)試、流量回放空凸、流量染色
  11. 故障系列嚎花;突襲、重現(xiàn)呀洲、演練
  12. 分布式的數(shù)據(jù)一致性
  13. 文件操作紊选;es、hive
  14. 注冊(cè)中心道逗;zookeeper翰苫、Eureka
  15. 互聯(lián)網(wǎng)工程開(kāi)發(fā)技術(shù)棧奔缠;spring牌借、mybaits了赌、網(wǎng)關(guān)、rpc(thrift, grpc, dubbo)吏夯、mq此蜈、緩存redis、分庫(kù)分表锦亦、定時(shí)任務(wù)舶替、分布式事物令境、限流杠园、熔斷、降級(jí)
  16. 數(shù)據(jù)庫(kù)binlog解析
  17. 架構(gòu)設(shè)計(jì)舔庶;DDD領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)抛蚁、微服務(wù)陈醒、服務(wù)治理
  18. 容器;k8s, docker
  19. 分布式存儲(chǔ)瞧甩;ceph
  20. 服務(wù)istio
  21. 壓測(cè) jmter
  22. Jenkins-部署java代碼項(xiàng)目 + ansible
  23. 全鏈路監(jiān)控钉跷,分布式追蹤
  24. 語(yǔ)音識(shí)別、語(yǔ)音合成
  25. lvs nginx haproxy iptables
  26. hadoop mapreduce hive sqoop hbase flink kylin druid

好肚逸,現(xiàn)在開(kāi)始就搞一下其中的一個(gè)技術(shù)點(diǎn) ASM爷辙,看看它的真面目。那么學(xué)習(xí)之前先看下他有什么用途朦促;

1.類的代理膝晾,如cglib

2.混沌工程

3.反向工程

4.結(jié)合 javaagent 做到非入侵式監(jiān)控,方法耗時(shí)务冕、日志血当、機(jī)器性能等等

5.破解

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD,那這種技術(shù)棧你永遠(yuǎn)碰不到

為了更方便的學(xué)習(xí)ASM禀忆,我將《ASM4使用手冊(cè)》以及一些技術(shù)點(diǎn)整理成在線文檔臊旭,可以隨時(shí)方便查閱(asm.itstack.org);

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD箩退,那這種技術(shù)棧你永遠(yuǎn)碰不到

二离熏、環(huán)境配置

1.jdk 1.8

2.idea 2019.3.1

3.asm-commons 6.2.1

三、工程信息

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD戴涝,那這種技術(shù)棧你永遠(yuǎn)碰不到
  • itstack-demo-asm-01:字節(jié)碼編程撤奸,HelloWorld
  • itstack-demo-asm-02:字節(jié)碼編程,兩數(shù)之和
  • itstack-demo-asm-03:字節(jié)碼增強(qiáng)喊括,輸出入?yún)?/li>
  • itstack-demo-asm-04:字節(jié)碼增強(qiáng)胧瓜,調(diào)用外部方法

四、HelloWorld還可以這樣寫(xiě)

你所熟悉的HelloWorld是不這樣郑什;

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD府喳,那這種技術(shù)棧你永遠(yuǎn)碰不到

那你有嘗試反解析下他的類查看下匯編指令嗎,javap -c HelloWorld

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD蘑拯,那這種技術(shù)棧你永遠(yuǎn)碰不到
【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD钝满,那這種技術(shù)棧你永遠(yuǎn)碰不到

如果你還感興趣其他指令,可以參考這個(gè)字節(jié)碼指令表:Go!

好申窘! 以上呢弯蚜,是我很熟悉的一段代碼了,那么現(xiàn)在我們把這段代碼用ASM方式寫(xiě)出來(lái)剃法;

import org.objectweb.asm.ClassWriter;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Opcodes;

private static byte[] generate() {

ClassWriter classWriter = new ClassWriter(0);// 定義對(duì)象頭碎捺;版本號(hào)、修飾符、全類名收厨、簽名晋柱、父類、實(shí)現(xiàn)的接口classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "org/itstack/demo/asm/AsmHelloWorld", null, "java/lang/Object", null);// 添加方法诵叁;修飾符雁竞、方法名、描述符拧额、簽名碑诉、異常MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);// 執(zhí)行指令;獲取靜態(tài)屬性methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");// 加載常量 load constantmethodVisitor.visitLdcInsn("Hello World");// 調(diào)用方法methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);// 返回methodVisitor.visitInsn(Opcodes.RETURN);// 設(shè)置操作數(shù)棧的深度和局部變量的大小methodVisitor.visitMaxs(2, 1);// 方法結(jié)束methodVisitor.visitEnd();// 類完成classWriter.visitEnd();// 生成字節(jié)數(shù)組return classWriter.toByteArray();

}

以上的代碼侥锦,“小朋友联贩,你是否有很多問(wèn)好???^1024”,其實(shí)以上的代碼都是來(lái)自于 ASM 框架的代碼捎拯,這里面所有的操作與我們使用使用 javap -c XXX 所反解析出的字節(jié)碼是一樣的泪幌,只不過(guò)是反過(guò)來(lái)使用指令來(lái)編寫(xiě)代碼。

1.定義一個(gè)類的生成 ClassWriter

2.設(shè)定版本署照、修飾符祸泪、全類名、簽名建芙、父類没隘、實(shí)現(xiàn)的接口,其實(shí)也就是那句禁荸;public class HelloWorld

3.接下來(lái)開(kāi)始創(chuàng)建方法右蒲,方法同樣需要設(shè)定;修飾符赶熟、方法名瑰妄、描述符等。這里面有幾個(gè)固定標(biāo)識(shí)映砖;

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD间坐,那這種技術(shù)棧你永遠(yuǎn)碰不到

4.執(zhí)行指令;獲取靜態(tài)屬性邑退。主要是獲得 System.out

5.加載常量 load constant竹宋,輸出我們的HelloWorld methodVisitor.visitLdcInsn("Hello World");

6.最后是調(diào)用輸出方法并設(shè)置空返回,同時(shí)在結(jié)尾要設(shè)置操作數(shù)棧的深度和局部變量的大小

這樣輸出一個(gè) HelloWorld 是不還是蠻有意思的地技,雖然你可能覺(jué)得這編碼起來(lái)實(shí)在太難了吧蜈七,也非常難理解。首先如果你看過(guò)我的專欄莫矗,用《Java寫(xiě)一個(gè)Jvm虛擬機(jī)》飒硅,那么你可能會(huì)感受到這里面的知識(shí)點(diǎn)還是不那么陌生的砂缩。另外這里的編寫(xiě),ASM還提供了插件狡相,可以方便的讓你開(kāi)發(fā)字節(jié)碼梯轻。接下來(lái)就介紹一下使用方式食磕。

五尽棕、有插件的幫助字節(jié)碼開(kāi)發(fā)也不是很難

對(duì)于新人來(lái)說(shuō)如果用字節(jié)碼增強(qiáng)開(kāi)發(fā)一些東西確實(shí)挺難,尤其是一些復(fù)雜的代碼塊使用字節(jié)碼指令操作還是很有難度的彬伦。那么滔悉,其實(shí)也是有簡(jiǎn)單辦法就是使用 ASM 插件。這個(gè)插件可以很輕松的讓你看到一段代碼的指令碼以及如何用ASM去開(kāi)發(fā)单绑。

1.安裝插件(ASM Bytecode Outline)

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD回官,那這種技術(shù)棧你永遠(yuǎn)碰不到

2.測(cè)試使用

【開(kāi)發(fā)者成長(zhǎng)】如果你只寫(xiě)CRUD,那這種技術(shù)棧你永遠(yuǎn)碰不到

是不是看到有插件的幫助下搂橙,心里有所激動(dòng)了歉提,至少寫(xiě)這樣的東西有了抓手。這樣你就可以很方便的去操作一些增強(qiáng)字節(jié)碼的功能了区转。

六苔巨、用字節(jié)碼寫(xiě)出一個(gè)兩數(shù)之和計(jì)算

好!有了上面的插件废离,也有了一些基礎(chǔ)知識(shí)的了解侄泽。那么我們開(kāi)發(fā)一個(gè)計(jì)算兩數(shù)之和的方法,之后運(yùn)行計(jì)算結(jié)果蜻韭。

這是我們的目標(biāo)

使用字節(jié)碼編程方式實(shí)現(xiàn)

  • 上面有兩個(gè)括號(hào) {}悼尾,第一個(gè)是用于生成一個(gè)空的構(gòu)造函數(shù)
  • 接下來(lái)的指令就比較簡(jiǎn)單了,首先使用 ILOAD 進(jìn)行數(shù)值的兩次壓棧也就是弄到操作數(shù)棧里去操作肖方,接下來(lái)開(kāi)始執(zhí)行 IADD闺魏,將兩數(shù)相加。
  • 最后返回結(jié)果 IRETURN ,注意是返回的 I 類型俯画。到此這段方法快就實(shí)現(xiàn)完成了舷胜。反編譯后如下;

這段執(zhí)行操作和我們?cè)谑褂?java 的反射操作一樣活翩,也是比較容易的烹骨。此時(shí)我們是調(diào)用了新的字節(jié)碼類,同時(shí)還將字節(jié)碼輸出方便我們查看生成的 class 類材泄。

七沮焕、在原有方法上字節(jié)碼增強(qiáng)監(jiān)控耗時(shí)

到這我們基本了解到通過(guò)字節(jié)碼編程,可以動(dòng)態(tài)的生成一個(gè)類拉宗。但是在實(shí)際使用的過(guò)程中峦树,我們可能有的時(shí)候是需要修改一個(gè)原有的方法辣辫,在開(kāi)始和結(jié)尾添加一些代碼,來(lái)監(jiān)控這個(gè)方法的耗時(shí)魁巩。這也是非侵入式監(jiān)控的最基本模型急灭。

整體的代碼塊有點(diǎn)大,我們可以分為塊來(lái)看谷遂,如下葬馋;

ClassReader cr = new ClassReader(MyMethod.class.getName()); 讀取原有類,也是字節(jié)碼增強(qiáng)的開(kāi)始ClassVisitor cv = new ProfilingClassAdapter(cw, MyMethod.class.getSimpleName()); 開(kāi)始增強(qiáng)字節(jié)碼onMethodEnter肾扰,onMethodExit畴嘶,在方法進(jìn)入和方法退出時(shí)添加耗時(shí)執(zhí)行的代碼。

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

直接運(yùn)行TestMonitor.java集晚;

八窗悯、字節(jié)碼控制打印方法的入?yún)?/strong>

那么除了可以監(jiān)控方法的執(zhí)行耗時(shí),還可以將方法的入?yún)⑿畔⑦M(jìn)行打印出來(lái)偷拔。這樣就可以在一些異常情況下蒋院,看到日志信息。

其他代碼與上面相同莲绰,這里只列一下修改的地方

從這里可以看到欺旧,在方法進(jìn)入時(shí)候使用指令碼 GETSTATIC,獲取輸出對(duì)象類

  • 接下來(lái)使用 ALOAD钉蒲,從局部變量1中裝載引用類型值入棧
  • 最后輸出入?yún)⑿畔?/li>
  • 測(cè)試結(jié)果:

直接運(yùn)行TestMonitor.java切端;

九、用字節(jié)碼增強(qiáng)調(diào)用外部方法好顷啼!那么執(zhí)行到這踏枣,我們可以想到如果只是將一些信息打印到控制臺(tái)還是沒(méi)有辦法做業(yè)務(wù)的,我們需要在這個(gè)時(shí)候?qū)⒏鞣N屬性信息調(diào)用外部的類钙蒙,進(jìn)行發(fā)送到服務(wù)端茵瀑。比如使用;mq躬厌、日志等马昨。

定義日志信息輸出類

十、總結(jié)

  • 高級(jí)編程技術(shù)的內(nèi)容還不止于此扛施,不要只為了一時(shí)的功能實(shí)現(xiàn)鸿捧,而放棄深挖深究的機(jī)會(huì)。也許就是你不斷的增強(qiáng)拓展個(gè)人的知識(shí)技能疙渣,才讓你越來(lái)越與眾不同匙奴。
  • ASM 這種字節(jié)碼編程的應(yīng)用是非常廣的,但可能確實(shí)平時(shí)看不到的妄荔,因?yàn)樗际桥c其他框架結(jié)合一起作為支撐服務(wù)使用泼菌。像這樣的技術(shù)還有很多谍肤,比如 javaassit、netty等等哗伯。
  • 對(duì)于真的要學(xué)習(xí)一樣技術(shù)時(shí)荒揣,不要只看爽文,但爽文也確實(shí)給了你敲門磚焊刹。當(dāng)你要徹底的掌握某個(gè)知識(shí)的時(shí)候系任,最重要的是成體系的學(xué)習(xí)!壓榨自己的時(shí)間伴澄,做有意義的事赋除,是3-7年開(kāi)發(fā)人員最正確的事
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阱缓,一起剝皮案震驚了整個(gè)濱河市非凌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荆针,老刑警劉巖敞嗡,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異航背,居然都是意外死亡喉悴,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門玖媚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)箕肃,“玉大人,你說(shuō)我怎么就攤上這事今魔∩紫瘢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵错森,是天一觀的道長(zhǎng)吟宦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)涩维,這世上最難降的妖魔是什么殃姓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮瓦阐,結(jié)果婚禮上蜗侈,老公的妹妹穿的比我還像新娘。我一直安慰自己睡蟋,他們只是感情好踏幻,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著薄湿,像睡著了一般叫倍。 火紅的嫁衣襯著肌膚如雪偷卧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,196評(píng)論 1 308
  • 那天吆倦,我揣著相機(jī)與錄音听诸,去河邊找鬼。 笑死蚕泽,一個(gè)胖子當(dāng)著我的面吹牛晌梨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播须妻,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼仔蝌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了荒吏?” 一聲冷哼從身側(cè)響起敛惊,我...
    開(kāi)封第一講書(shū)人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绰更,沒(méi)想到半個(gè)月后瞧挤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡儡湾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年特恬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徐钠。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡癌刽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尝丐,到底是詐尸還是另有隱情显拜,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布摊崭,位于F島的核電站讼油,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏呢簸。R本人自食惡果不足惜矮台,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望根时。 院中可真熱鬧瘦赫,春花似錦、人聲如沸蛤迎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)替裆。三九已至校辩,卻和暖如春窘问,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宜咒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工惠赫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人故黑。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓儿咱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親场晶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子混埠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 理解AOP 之前幾篇文章我們?cè)敿?xì)介紹了AOP的幾種技術(shù)方案,由于AOP技術(shù)復(fù)雜多樣诗轻,實(shí)際需求也不盡相同钳宪,那么我們應(yīng)...
    wanderingGuy閱讀 5,050評(píng)論 0 15
  • 前言 在上篇文章中,我們以AspectJ為引子介紹了AOP及其設(shè)計(jì)思想概耻,傳送門Android AspectJ詳解使套,...
    wanderingGuy閱讀 9,117評(píng)論 4 10
  • 前言 很早之前就寫(xiě)過(guò)面向切面的編程思想罐呼,主要學(xué)習(xí)了AOP的思想(參考:AOP簡(jiǎn)介)以及使用 AspectJ 實(shí)現(xiàn)簡(jiǎn)...
    Whyn閱讀 10,797評(píng)論 4 40
  • ASM介紹 ASM是一個(gè)字節(jié)碼操作庫(kù)鞠柄,它可以直接修改已經(jīng)存在的class文件或者生成class文件。ASM提供了一...
    嘮嗑008閱讀 8,865評(píng)論 7 38
  • 如果說(shuō)非要推薦一款滿足學(xué)生黨和化妝小白的口紅品牌,我一定會(huì)毫不猶豫的推薦wet n wild(濕又野)计螺。先不說(shuō)這個(gè)...
    仙女霸霸_cae4閱讀 218評(píng)論 0 0