偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

遠(yuǎn)程熱部署在美團(tuán)的落地實(shí)踐

原創(chuàng) 精選
開(kāi)發(fā) 架構(gòu)
Sonic是美團(tuán)內(nèi)部研發(fā)設(shè)計(jì)的一款用于熱部署的IDEA插件,本文其實(shí)現(xiàn)原理及落地的一些技術(shù)細(xì)節(jié)。

作者 | 凱哥 占峰 李晗等

Sonic是美團(tuán)內(nèi)部一款用于熱部署的IDEA插件。本文主要講述Sonic的實(shí)現(xiàn)細(xì)節(jié)以及底層原理,從IDEA插件到自動(dòng)化部署,再到沉浸式開(kāi)發(fā)產(chǎn)品閉環(huán),全方位講述了Sonic在美團(tuán)的落地與實(shí)踐經(jīng)驗(yàn)。目前業(yè)界對(duì)標(biāo)的產(chǎn)品并不多,希望本文能對(duì)從事聯(lián)調(diào)/開(kāi)發(fā)/測(cè)試等相關(guān)方向的同學(xué)有所幫助或啟發(fā)。

Sonic是美團(tuán)內(nèi)部研發(fā)設(shè)計(jì)的一款用于熱部署的IDEA插件,本文其實(shí)現(xiàn)原理及落地的一些技術(shù)細(xì)節(jié)。在閱讀本文之前,建議大家先熟悉一下Spring源碼?、Spring MVC 源碼 、Spring Boot源碼 、Agent字節(jié)碼增強(qiáng)?、Javassist?、Classloader等相關(guān)知識(shí)。?

1 前言

1.1 什么是熱部署

所謂熱部署,就是在應(yīng)用正在運(yùn)行時(shí)升級(jí)軟件,卻不需要重新啟動(dòng)應(yīng)用。對(duì)于Java應(yīng)用程序來(lái)說(shuō),熱部署就是在運(yùn)行時(shí)更新Java類(lèi)文件,同時(shí)觸發(fā)Spring以及其他常用第三方框架的一系列重新加載的過(guò)程。在這個(gè)過(guò)程中不需要重新啟動(dòng),并且修改的代碼實(shí)時(shí)生效,好比是戰(zhàn)斗機(jī)在空中完成加油,不需要戰(zhàn)斗機(jī)熄火降落,一系列操作都在“運(yùn)行”狀態(tài)來(lái)完成。

1.2 為什么我們需要熱部署

據(jù)了解,美團(tuán)內(nèi)部很多工程師每天本地重啟服務(wù)高達(dá)5~12次,單次大概3~8分鐘,每天向Cargo(美團(tuán)內(nèi)部測(cè)試環(huán)境管理工具)部署3~5次,單次時(shí)長(zhǎng)20~45分鐘,部署頻繁頻次高、耗時(shí)長(zhǎng),嚴(yán)重影響了系統(tǒng)上線(xiàn)的效率。而插件提供的本地和遠(yuǎn)程熱部署功能,可讓將代碼變更“秒級(jí)”生效。一般而言,開(kāi)發(fā)者日常工作主要分為開(kāi)發(fā)自測(cè)和聯(lián)調(diào)兩個(gè)場(chǎng)景,下面將分別介紹熱部署在每個(gè)場(chǎng)景中發(fā)揮的作用。

圖 1

1.2.1 開(kāi)發(fā)自測(cè)場(chǎng)景

一般來(lái)講,在用插件之前,開(kāi)發(fā)者修改完代碼還需等待3~8分鐘啟動(dòng)時(shí)間,然后手動(dòng)構(gòu)造請(qǐng)求或協(xié)調(diào)上游發(fā)請(qǐng)求,耗時(shí)且費(fèi)力。在使用完熱部署插件后,修改完代碼可以一鍵增量部署,讓變更“秒級(jí)”生效,能夠做到快速自測(cè)。而對(duì)于那些無(wú)法本地啟動(dòng)項(xiàng)目,也可以通過(guò)遠(yuǎn)程熱部署功能使代碼變更“秒級(jí)”生效。

圖 2

1.2.2 聯(lián)調(diào)場(chǎng)景

通常情況下,在使用插件之前,開(kāi)發(fā)者修改代碼經(jīng)過(guò)20~35分鐘的漫長(zhǎng)部署,需要聯(lián)系上游聯(lián)調(diào)開(kāi)發(fā)者發(fā)起請(qǐng)求,一直要等到遠(yuǎn)程服務(wù)器查看日志,才能確認(rèn)代碼生效。在使用熱部署插件之后,開(kāi)發(fā)者修改代碼遠(yuǎn)程熱部署能夠秒級(jí)(2~3s)生效,開(kāi)發(fā)者直接發(fā)起服務(wù)調(diào)用,可以節(jié)省大量的碎片化時(shí)間(熱部署插件還具備流量回放、遠(yuǎn)程調(diào)用、遠(yuǎn)程反編譯等功能,可配合進(jìn)行使用)。

圖 3

所以,熱部署插件希望解決的痛點(diǎn)是:在可控的條件內(nèi),幫助開(kāi)發(fā)者減少頻繁編譯部署的次數(shù),節(jié)省碎片化的時(shí)間。最終為開(kāi)發(fā)者每天節(jié)約出一定量的編碼時(shí)間。

1.3 熱部署難在哪

為什么業(yè)界目前沒(méi)有好用的開(kāi)源工具?因?yàn)闊岵渴鸩坏韧跓嶂貑ⅲ馮omcat或者Spring Boot DevTools此類(lèi)熱重啟模式需要重新加載項(xiàng)目,性能較差。增量熱部署難度較大,需要兼容常用的中間件版本,需要深入啟動(dòng)銷(xiāo)毀加載流程。以美團(tuán)為例,我們需要對(duì)JPDA(Java Platform Debugger Architecture)、Java Agent、ASM字節(jié)碼增強(qiáng)、Classloader、Spring框架、Spring Boot框架、MyBatis框架、Mtthrift(美團(tuán)RPC框架)、Zebra(美團(tuán)持久層框架)、Pigeon(美團(tuán)RPC框架),MDP(美團(tuán)快速開(kāi)發(fā)框架)、XFrame(美團(tuán)快速開(kāi)發(fā)腳手架)、Crane(美團(tuán)分布式任務(wù)調(diào)度框架)等眾多框架和技術(shù)原理深入了解才能做到全面的兼容和支持。另外,還需要IDEA插件開(kāi)發(fā)能力,形成整體的產(chǎn)品解決方案閉環(huán),美團(tuán)的熱部署插件Sonic正是在這種背景下應(yīng)運(yùn)而生。

圖 4

1.4 Sonic可以做什么

Sonic是美團(tuán)內(nèi)部研發(fā)設(shè)計(jì)的一款I(lǐng)DEA插件,旨在通過(guò)低代碼開(kāi)發(fā)輔助遠(yuǎn)程/本地?zé)岵渴穑鉀QCoding、單測(cè)編寫(xiě)執(zhí)行、自測(cè)聯(lián)調(diào)等階段的效率問(wèn)題,提高開(kāi)發(fā)者的編碼產(chǎn)出效率。數(shù)據(jù)統(tǒng)計(jì)表明,開(kāi)發(fā)者日常大概有35%時(shí)間用于編碼的產(chǎn)出。如果想提高研發(fā)效率,要么擴(kuò)大編碼產(chǎn)出的時(shí)間占比,要么提高編碼階段的產(chǎn)出效率,而Sonic則聚焦提高編碼階段的產(chǎn)出效率。目前,使用Sonic熱部署可以解決大部分代碼重復(fù)構(gòu)建的問(wèn)題。Sonic可以使用戶(hù)在本地編寫(xiě)代碼一鍵部署到遠(yuǎn)程環(huán)境,修改代碼、部署、聯(lián)調(diào)請(qǐng)求、查看日志,循環(huán)反復(fù)。如果不考慮代碼修改時(shí)間,通常一個(gè)循環(huán)需要20~35分鐘,而使用Sonic可以把整個(gè)時(shí)長(zhǎng)縮短至5~10秒,而且能夠給開(kāi)發(fā)者帶來(lái)高效沉浸式的開(kāi)發(fā)體驗(yàn)。在實(shí)際編碼工作中,多文件修改是家常便飯,Sonic對(duì)多文件的熱部署能力尤為突出,它可以通過(guò)依賴(lài)分析等手段來(lái)對(duì)多文件批量進(jìn)行遠(yuǎn)程熱部署,并且支持Spring Bean Class、普通Class、Spring XML、MyBatis XML等多類(lèi)型文件混合熱部署。下面的動(dòng)圖就演示了多文件復(fù)查場(chǎng)景下的增量熱部署:

那么跟業(yè)界現(xiàn)有的產(chǎn)品相比,Sonic有哪些優(yōu)劣勢(shì)呢?下面我們嘗試給出幾種產(chǎn)品的對(duì)比,僅供大家參考:

上表未把Sofa-Ark、Osgi、Arthas列舉,此類(lèi)屬于插件化、模塊化應(yīng)用框架,以及Java在線(xiàn)診斷工具,核心能力非熱部署。值得注意的是,Spring Boot DevTools只能應(yīng)用在Spring Boot項(xiàng)目中,并且它不是增量熱部署,而是通過(guò)Classloader迭代的方式重啟項(xiàng)目,對(duì)大項(xiàng)目而言,性能上是無(wú)法接受的。雖然,JRebel支持三方插件較多,生態(tài)龐大,但是對(duì)于國(guó)產(chǎn)的插件不支持,例如FastJson等,同時(shí)它還存在遠(yuǎn)程熱部署配置局限,對(duì)于公司內(nèi)部的中間件需要個(gè)性化開(kāi)發(fā),并且是商業(yè)軟件,整體的使用成本較高。

1.5 Sonic遠(yuǎn)程熱部署落地推廣的實(shí)踐經(jīng)驗(yàn)

相信大家都知道,對(duì)于技術(shù)產(chǎn)品的推廣,尤其是開(kāi)發(fā)、測(cè)試階段使用的產(chǎn)品,由于遠(yuǎn)離線(xiàn)上環(huán)境,推動(dòng)力、執(zhí)行力、產(chǎn)品功能閉環(huán)能否做好,是決定著該產(chǎn)品是否能在企業(yè)內(nèi)部落地并得到大多數(shù)人認(rèn)可的重要的一環(huán)。此外,因?yàn)楹芏嚅_(kāi)發(fā)者在開(kāi)發(fā)、測(cè)試階段已逐漸形成了“固化動(dòng)作”,如何改變這些用戶(hù)的行為,讓他們擁抱新產(chǎn)品,也是Sonic面臨的艱巨挑戰(zhàn)之一。我們從主動(dòng)溝通、零成本(或極低成本)快速接入、自動(dòng)化腳本,以及產(chǎn)品自動(dòng)診斷、收集反饋等方向出發(fā),踐行出了四條原則。

圖 6

2 整體設(shè)計(jì)方案

2.1 Sonic結(jié)構(gòu)

Sonic插件由4大部分組成,包括腳本端、插件端、Agent端,以及Sonic服務(wù)端。腳本端負(fù)責(zé)自動(dòng)化構(gòu)建Sonic啟動(dòng)參數(shù)、服務(wù)啟動(dòng)等集成工作;IDEA插件端集成環(huán)境為開(kāi)發(fā)者提供更便捷的熱部署服務(wù);Agent端隨項(xiàng)目啟動(dòng)負(fù)責(zé)熱部署的功能實(shí)現(xiàn);服務(wù)端則負(fù)責(zé)收集熱部署信息、失敗上報(bào)等統(tǒng)計(jì)工作。如下圖所示:

圖 7

2.2 走進(jìn)Agent

2.2.1 Instrumentation類(lèi)常用API

public interface Instrumentation {

    //增加一個(gè)Class 文件的轉(zhuǎn)換器,轉(zhuǎn)換器用于改變 Class 二進(jìn)制流的數(shù)據(jù),參數(shù) canRetransform 設(shè)置是否允許重新轉(zhuǎn)換。
    void addTransformer(ClassFileTransformer transformerboolean canRetransform);

    //在類(lèi)加載之前,重新定義 Class 文件,ClassDefinition 表示對(duì)一個(gè)類(lèi)新的定義,
    //如果在類(lèi)加載之后,需要使用 retransformClasses 方法重新定義。addTransformer方法配置之后,后續(xù)的類(lèi)加載都會(huì)被Transformer攔截。
    //對(duì)于已經(jīng)加載過(guò)的類(lèi),可以執(zhí)行retransformClasses來(lái)重新觸發(fā)這個(gè)Transformer的攔截。類(lèi)加載的字節(jié)碼被修改后,除非再次被retransform,否則不會(huì)恢復(fù)。
    void addTransformer(ClassFileTransformer transformer);

    //刪除一個(gè)類(lèi)轉(zhuǎn)換器
    boolean removeTransformer(ClassFileTransformer transformer);
    
    //是否允許對(duì)class retransform
    boolean isRetransformClassesSupported();

    //在類(lèi)加載之后,重新定義 Class。這個(gè)很重要,該方法是1.6 之后加入的,事實(shí)上,該方法是 update 了一個(gè)類(lèi)。
    void retransformClasses(Class<?>... classesthrows UnmodifiableClassException;
   
    //是否允許對(duì)class重新定義
    boolean isRedefineClassesSupported();

    //此方法用于替換類(lèi)的定義,而不引用現(xiàn)有的類(lèi)文件字節(jié),就像從源代碼重新編譯以進(jìn)行修復(fù)和繼續(xù)調(diào)試時(shí)所做的那樣。
    //在要轉(zhuǎn)換現(xiàn)有類(lèi)文件字節(jié)的地方(例如在字節(jié)碼插裝中),應(yīng)該使用retransformClasses。
    //該方法可以修改方法體、常量池和屬性值,但不能新增、刪除、重命名屬性或方法,也不能修改方法的簽名
    void redefineClasses(ClassDefinition... definitionsthrows  ClassNotFoundExceptionUnmodifiableClassException;

    //獲取已經(jīng)被JVM加載的class,有className可能重復(fù)(可能存在多個(gè)classloader)
    @SuppressWarnings("rawtypes")
    Class[] getAllLoadedClasses();
}



2.2.2 Instrument簡(jiǎn)介

Instrument的底層實(shí)現(xiàn)依賴(lài)于JVMTI(JVM Tool Interface),它是JVM暴露出來(lái)的一些供用戶(hù)擴(kuò)展的接口集合,JVMTI是基于事件驅(qū)動(dòng)的,JVM每執(zhí)行到一定的邏輯就會(huì)調(diào)用一些事件的回調(diào)接口(如果存在),這些接口可以供開(kāi)發(fā)者去擴(kuò)展自己的邏輯。JVMTIAgent是一個(gè)利用JVMTI暴露出來(lái)的接口提供了代理啟動(dòng)時(shí)加載(Agent On Load)、代理通過(guò)Attach形式加載(Agent On Attach)和代理卸載(Agent On Unload)功能的動(dòng)態(tài)庫(kù)。而Instrument Agent可以理解為一類(lèi)JVMTIAgent動(dòng)態(tài)庫(kù),別名是JPLISAgent(Java Programming Language Instrumentation Services Agent),也就是專(zhuān)門(mén)為Java語(yǔ)言編寫(xiě)的插樁服務(wù)提供支持的代理。

2.2.3 啟動(dòng)時(shí)和運(yùn)行時(shí)加載Instrument Agent過(guò)程

圖 8

2.3 那些年JVM和HotSwap之間的“相愛(ài)相殺”

圍繞著Method Body的HotSwap JVM一直在進(jìn)行改進(jìn)。從1.4版本開(kāi)始,JPDA引入HotSwap機(jī)制(JPDA Enhancements),實(shí)現(xiàn)Debug時(shí)的Method Body的動(dòng)態(tài)性。大家可參考文檔:??enhancements1.4???。1.5版本開(kāi)始通過(guò)JVMTI實(shí)現(xiàn)的java.lang.instrument(Java Platform SE 8)的Premain方式,實(shí)現(xiàn)Agent方式的動(dòng)態(tài)性(JVM啟動(dòng)時(shí)指定Agent)。大家可參考文檔:??package-summary???。1.6版本又增加Agentmain方式,實(shí)現(xiàn)運(yùn)行時(shí)動(dòng)態(tài)性(通過(guò)The Attach API 綁定到具體VM)。大家可參考文檔:??package-summary?? ?;緦?shí)現(xiàn)是通過(guò)JVMTI的retransformClass/redefineClass進(jìn)行method、body級(jí)的字節(jié)碼更新,ASM、CGLib基本都是圍繞這些在做動(dòng)態(tài)性。但是針對(duì)Class的HotSwap一直沒(méi)有動(dòng)作(比如Class添加method、添加field、修改繼承關(guān)系等等),為什么會(huì)這樣呢?因?yàn)閺?fù)雜度過(guò)高,且沒(méi)有很高的回報(bào)。

2.4 Sonic如何解決Instrumentation的局限性

由于JVM限制,JDK 7和JDK 8都不允許改類(lèi)結(jié)構(gòu),比如新增字段,新增方法和修改類(lèi)的父類(lèi)等,這對(duì)于Spring項(xiàng)目來(lái)說(shuō)是致命的。比如開(kāi)發(fā)同學(xué)想修改一個(gè)Spring Bean,新增一個(gè)@Autowired字段,此類(lèi)場(chǎng)景在實(shí)際應(yīng)用時(shí)很多,所以Sonic對(duì)此類(lèi)場(chǎng)景的支持必不可少。那么,具體是如何做到的呢?這里要提一下“大名鼎鼎”的Dcevm。Dcevm(DynamicCode Evolution Virtual Machine)是Java Hostspot的補(bǔ)?。▏?yán)格上來(lái)說(shuō)是修改),允許(并非無(wú)限制)在運(yùn)行環(huán)境下修改加載的類(lèi)文件。當(dāng)前虛擬機(jī)只允許修改方法體(Method,Body),而Decvm可以增加、刪除類(lèi)屬性、方法,甚至改變一個(gè)類(lèi)的父類(lèi),Dcevm是一個(gè)開(kāi)源項(xiàng)目,遵從GPL 2.0協(xié)議。更多關(guān)于Dcevm的介紹,大家可以參考:??Wuerthinger10a???以及??GitHub Decvm???。值得一提的是,在美團(tuán)內(nèi)部,針對(duì)Dcevm的安裝,Sonic已經(jīng)打通??HULK??,集成發(fā)布鏡像即可完成(本地?zé)岵渴鹂山Y(jié)合插件功能實(shí)現(xiàn)一鍵安裝熱部署環(huán)境)。

3 Sonic熱部署技術(shù)解析

3.1 Sonic整體架構(gòu)模型

上一章節(jié)我們主要介紹了Sonic的組成。下圖詳細(xì)介紹了Sonic在運(yùn)行期間各個(gè)組成部分的工作職責(zé),由它們形成一整套完備的技術(shù)產(chǎn)品落地閉環(huán)方案:

圖 9

3.2 Sonic功能流轉(zhuǎn)

Sonic通過(guò)NIO監(jiān)聽(tīng)本地文件變更,觸發(fā)文件變更事件,例如Class新增、Class修改、Spring Bean重載等事件流程。下圖展示了一次熱部署單個(gè)文件的生命周期:

圖 10

3.3 文件監(jiān)聽(tīng)

Sonic首先會(huì)在本地和遠(yuǎn)程預(yù)定義兩個(gè)目錄,??/var/tmp/sonic/extraClasspath???和??/var/tmp/sonic/classes??。extraClasspath為Sonic自定義的拓展Classpath URL,classes為Sonic監(jiān)聽(tīng)的目錄,當(dāng)有文件變更時(shí),通過(guò)IDEA插件來(lái)部署到遠(yuǎn)程/本地,觸發(fā)Agent的監(jiān)聽(tīng)目錄,來(lái)繼續(xù)下面的熱加載邏輯:

圖 11

為什么Sonic不直接替換用戶(hù)ClassPath下面的資源文件呢?因?yàn)榭紤]到業(yè)務(wù)方WAR包的API項(xiàng)目、Spring Boot、Tomcat項(xiàng)目、Jetty項(xiàng)目等,都是以JAR包來(lái)啟動(dòng)的,這樣是無(wú)法直接修改用戶(hù)的Class文件的。即使是用戶(hù)項(xiàng)目可以修改,直接操作用戶(hù)的Class,也會(huì)帶來(lái)一系列的安全問(wèn)題。所以,Sonic采用拓展ClassPath URL路徑來(lái)實(shí)現(xiàn)文件的修改和新增。并且存在這么一種場(chǎng)景,多個(gè)業(yè)務(wù)側(cè)的項(xiàng)目引入相同的JAR包,在JAR里面配置MyBatis的XML和注解。在此類(lèi)情況下,Sonic沒(méi)有辦法直接來(lái)修改JAR包中源文件,通過(guò)拓展路徑的方式可以不需要關(guān)注JAR包,來(lái)修改JAR包中某一文件和XML。同理,采用此類(lèi)方法可以進(jìn)行整個(gè)JAR包的熱替換。下面我們簡(jiǎn)單介紹一下Sonic的核心監(jiān)聽(tīng)器,如下圖所示:

圖 12

3.4 JVM Class Reload

JVM的字節(jié)碼批量重載邏輯,通過(guò)新的字節(jié)碼二進(jìn)制流和舊的Class對(duì)象生成ClassDefinition定義,instrumentation.redefineClasses(definitions),來(lái)觸發(fā)JVM重載,重載過(guò)后將觸發(fā)初始化時(shí)Spring插件注冊(cè)的Transfrom。接下來(lái),我們簡(jiǎn)單講解一下Spring是怎么重載的。新增class Sonic如何保證可以加載到Classloader上下文中?由于項(xiàng)目在遠(yuǎn)程執(zhí)行,所以運(yùn)行環(huán)境復(fù)雜,有可能是JAR包方式啟動(dòng)(Spring Boot),也有可能是普通項(xiàng)目,也有可能是War Web項(xiàng)目,針對(duì)此類(lèi)情況Sonic做了一層Classloader URL拓展。

圖 13

User ClassLoader是框架自定義的ClassLoader統(tǒng)稱(chēng),例如Jetty項(xiàng)目是WebAppclassLoader。其中Urlclasspath為當(dāng)前項(xiàng)目的lib文件件下,例如Spring Boot項(xiàng)目也是從當(dāng)前項(xiàng)目BOOT-INF/lib/路徑中加載CLass等等,不同框架的自定義位置稍有不同。所以針對(duì)此類(lèi)情況,Agent必須拿到用戶(hù)的自定義Classloader,如果是常規(guī)方式啟動(dòng)的,比如普通Spring XML項(xiàng)目,借助Plus(美團(tuán)內(nèi)部服務(wù)發(fā)布平臺(tái))發(fā)布,此類(lèi)沒(méi)有自定義Classloader,是默認(rèn)AppClassLoader,所以Agent在用戶(hù)項(xiàng)目啟動(dòng)過(guò)程中,借助字節(jié)碼增強(qiáng)的方式來(lái)獲取到真正的用戶(hù)Classloader。

圖 14

找到用戶(hù)使用的子Classloader之后,通過(guò)反射的方式來(lái)獲取Classloader中的元素Classpath,其中ClassPath中的URL就是當(dāng)前項(xiàng)目加載Class時(shí)需要的所有運(yùn)行時(shí)Class環(huán)境,并且包括三方的JAR包依賴(lài)等。Sonic獲取到URL數(shù)組,把Sonic自定義的拓展Classpath目錄加入到URL數(shù)組首位,這樣當(dāng)有新增Class時(shí),Sonic只需要將Class文件復(fù)制到拓展Classpath對(duì)應(yīng)的包目錄下面即可,當(dāng)有其他Bean依賴(lài)新增的Class時(shí),會(huì)從當(dāng)前目錄下面查找類(lèi)文件。為什么不直接對(duì)Appclassloader進(jìn)行加強(qiáng)?而是對(duì)框架的自定義Classloader進(jìn)行加強(qiáng)?

圖 15

考慮這樣一個(gè)場(chǎng)景,框架自定義類(lèi)加載器中有ClassA,此時(shí)用戶(hù)新增ClassB需要熱加載,B Class里面有A的引用關(guān)系,如果增強(qiáng)AppClassLoader,初始化B實(shí)例時(shí)ClassLoader。loadclass首先從UserClassLoader開(kāi)始加載ClassB的字節(jié)碼,依靠雙親委派原則,B被Appclassloader加載,因?yàn)锽依賴(lài)類(lèi)A,所以當(dāng)前AppClassLoader加載B一定是加載不到的,此時(shí)會(huì)拋出ClassNotFoundException異常。所以對(duì)類(lèi)加載器拓展,一定要拓展最上層的類(lèi)加載器,這樣才會(huì)達(dá)到使用者想要的效果。

3.5 Spring Bean重載

Spring Bean Reload過(guò)程中,Bean的銷(xiāo)毀和重啟流程,主要內(nèi)容如下圖展示:

圖 16

首先當(dāng)修改Java Class D時(shí),通過(guò)Spring ClasspathScan掃描校驗(yàn)當(dāng)前修改的Bean是否Sprin Bean(注解校驗(yàn)),然后觸發(fā)銷(xiāo)毀流程(BeanDefinitionRegistry.removeBeanDefinition),此方法會(huì)將當(dāng)前Spring上下文中的Bean D和依賴(lài)Spring Bean D的Bean C一并銷(xiāo)毀,但是作用范圍僅僅在當(dāng)前Spring上下文。如果C被子上下文中的Bean B依賴(lài),就無(wú)法更新子上下文中的依賴(lài)關(guān)系,當(dāng)有系統(tǒng)請(qǐng)求時(shí),Bean B中關(guān)聯(lián)的Bean C還是熱部署之前的對(duì)象,所以熱部署失敗。因此,在Spring初始化過(guò)程中,需要維護(hù)父子上下文的對(duì)應(yīng)關(guān)系,當(dāng)子上下文變時(shí)若變更范圍涉及到Bean B時(shí),需要重新更新子上下文中的依賴(lài)關(guān)系,當(dāng)有多上下文關(guān)聯(lián)時(shí)需要維護(hù)多上下文環(huán)境,且當(dāng)前上下文環(huán)境入口需要Reload。這里的入口是指:Spring MVC Controller、Mthrift和Pigeon,對(duì)不同的流量入口,采用不同的Reload策略。RPC框架入口主要操作為解綁注冊(cè)中心、重新注冊(cè)、重新加載啟動(dòng)流程等等,對(duì)Spring MVC Controller,主要是解綁和注冊(cè)URL Mappping來(lái)實(shí)現(xiàn)流量入口類(lèi)的變化切換。

3.6 Spring XML重載

當(dāng)用戶(hù)修改/新增Spring XML時(shí),需要對(duì)XML中所有Bean進(jìn)行重載。

圖 17

重新Reload之后,將Spring銷(xiāo)毀后重啟。需要注意的是:XML修改方式改動(dòng)較大,可能涉及到全局的AOP的配置以及前置和后置處理器相關(guān)的內(nèi)容,影響范圍為全局,所以目前只放開(kāi)普通的XML Bean標(biāo)簽的新增/修改,其他能力酌情逐步放開(kāi)。

3.7 MyBatis 熱部署

Spring MyBatis熱部署的主要處理流程是在啟動(dòng)期間獲取所有Configuration路徑,并維護(hù)它和Spring Context的對(duì)應(yīng)關(guān)系,在熱部署Class、XML時(shí)去匹配Configuration,從而重新加載Configuration以達(dá)到熱部署的目的。

圖 18

4 總結(jié)

4.1 熱部署功能一覽

上一章節(jié)主要講述了Spring Bean、Spring MVC、MyBatis的重載流程,Sonic還支持其它常用的開(kāi)發(fā)框架,豐富的框架支持和兼容能力是Sonic的基石,下面列舉一些Sonic支持的常用的第三方框架:

圖19

美團(tuán)內(nèi)部框架以及常用開(kāi)源框架截止目前,Sonic已經(jīng)支持絕大部分常用第三方框架的熱加載,常規(guī)業(yè)務(wù)開(kāi)發(fā)幾乎無(wú)需重啟服務(wù)。并且在美團(tuán)內(nèi)部的成功率已經(jīng)高達(dá)99.9%以上,真正地讓熱部署來(lái)代替常規(guī)部署構(gòu)建成為一種可能。

4.2 IDE插件集成

Sonic也提供了功能強(qiáng)大的IDEA插件,讓用戶(hù)進(jìn)行沉浸式開(kāi)發(fā),遠(yuǎn)程熱部署也變得更加便利。

圖 20

4.3 推廣使用情況

截止到發(fā)稿時(shí),Sonic在美團(tuán)使用人數(shù)3000+,應(yīng)用項(xiàng)目數(shù)量2000+。該項(xiàng)目還獲得了美團(tuán)內(nèi)部2020年下半年到家研發(fā)平臺(tái)“最佳效率團(tuán)隊(duì)”獎(jiǎng)。

5 作者簡(jiǎn)介

凱哥、占峰、李晗、龔炎、程驍、玉龍等,均來(lái)自美團(tuán)/到家研發(fā)平臺(tái)。

6 參考文章

?[1] 基于Javassist和Javaagent實(shí)現(xiàn)動(dòng)態(tài)切面[2] Spring MVC 源碼解析[3] Spring IOC源碼解析[4] MyBatis源碼解析[5] Spring Boot源碼解析[6] Spring AOP源碼解析[7] Spring事務(wù)源碼解析[8] Cglib源碼解析[9] JDK Proxy源碼解析[10] Dcevm簡(jiǎn)介[11] 字節(jié)碼增強(qiáng)技術(shù)探索[12] Javassist API

責(zé)任編輯:張燕妮 來(lái)源: 美團(tuán)技術(shù)團(tuán)隊(duì)
相關(guān)推薦

2022-08-09 09:18:47

優(yōu)化實(shí)踐

2024-03-20 14:22:55

遠(yuǎn)程熱部署

2018-07-13 09:53:27

移動(dòng)應(yīng)用美團(tuán)代碼

2022-03-25 10:47:59

架構(gòu)實(shí)踐美團(tuán)

2019-08-23 13:10:39

美團(tuán)點(diǎn)評(píng)Kubernetes集群管理

2022-04-15 15:46:06

數(shù)據(jù)視頻技術(shù)

2022-03-15 10:20:00

云原生系統(tǒng)實(shí)踐

2018-10-29 15:50:23

深度學(xué)習(xí)工程實(shí)踐技術(shù)

2017-02-20 19:23:13

2017-07-20 17:27:01

互聯(lián)網(wǎng)

2022-04-15 10:30:03

美團(tuán)技術(shù)實(shí)踐

2018-06-01 10:08:00

DBA美團(tuán)SQL

2022-08-12 12:23:28

神經(jīng)網(wǎng)絡(luò)優(yōu)化

2023-11-14 12:07:43

美團(tuán)沙龍

2018-03-28 09:53:50

Android架構(gòu)演進(jìn)

2022-02-14 16:08:15

開(kāi)源項(xiàng)目線(xiàn)程池動(dòng)態(tài)可監(jiān)控

2022-04-29 09:10:00

算法人工智能技術(shù)

2018-10-19 14:16:09

Flink數(shù)據(jù)倉(cāng)庫(kù)數(shù)據(jù)系統(tǒng)

2022-06-17 11:54:17

數(shù)據(jù)模型系統(tǒng)

2022-06-01 09:04:58

Kafka運(yùn)維副本遷移
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)