AOP—JVM SandBox—快速上手
原文作者:stingfire
原文地址:深入學(xué)習(xí)jvm-sandbox(安裝&快速上手)
目錄
一、安裝
1. 下載
2. 運(yùn)行安裝腳本
3. 閱讀安裝腳本
3.1 首先是定義安裝目錄變量
3.2 解析參數(shù)
3.3 拷貝文件
3.4 更新sandbox.sh腳本
3.5 輸出結(jié)果
二、快速上手
2.1 ATTACH方式啟動(dòng)
2.2 AGENT方式啟動(dòng)
2.3 實(shí)操(wiki例子:修復(fù)一個(gè)損壞了的鐘)
2.3.1 創(chuàng)建Clock類
2.3.2 創(chuàng)建修復(fù)Clock的模塊(module)
2.3.3 部署模塊
2.3.4 啟動(dòng)sandbox
2.3.5 執(zhí)行修復(fù)
一、安裝
jvm-sandbox的安裝非常簡(jiǎn)單,簡(jiǎn)言之就是執(zhí)行下載文件夾里的install-local.sh,下載地址請(qǐng)?jiān)L問(wèn)這里。
1. 下載
下載安裝包的zip文件解壓后目錄結(jié)構(gòu)如下:
這里面bin目錄下的sandbox.sh就是jvm-sandbox交互的命令行腳本,但是沒(méi)有安裝前不能直接使用,因?yàn)檫€有一些變量沒(méi)有定義。example、module、provider目錄下的各種jar文件就是各種用途的module文件(什么是module以后再做介紹,這里理解成一個(gè)個(gè)插件即可)。cfg目錄下是sandbox的配置文件,lib目錄下的jar文件是sandbox的核心運(yùn)行邏輯,以后再詳述。install-local.sh就是我們需要執(zhí)行的安裝文件咯,保障它有執(zhí)行權(quán)限并運(yùn)行。
2. 運(yùn)行安裝腳本
install-local.sh腳本運(yùn)行的參數(shù)很簡(jiǎn)單:
- -h : 幫助選項(xiàng),打印命令幫助信息。
- -p : 指定本地安裝目錄。如果不指定,則默認(rèn)安裝在"${HOME}/.opt"下,也就是當(dāng)前用戶主目錄下的 ~/.opt/ 下面。
腳本執(zhí)行完成后,輸出如下信息表明執(zhí)行成功。
至此,sandbox安裝完畢,可以開(kāi)始你的各種花式玩耍來(lái)練手了。SO EASY!!!
3. 閱讀安裝腳本
打開(kāi)解壓安裝包里的install-local.sh,可以發(fā)現(xiàn)安裝邏輯還是簡(jiǎn)單的。我們這里只介紹主要邏輯:
3.1 首先是定義安裝目錄變量
定義安裝目錄變量并且賦默認(rèn)值,也就是前面說(shuō)的如果不指定“-p“參數(shù)的默認(rèn)安裝目錄。
typeset SANDBOX_INSTALL_PREFIXtypeset DEFAULT_SANDBOX_INSTALL_PREFIX="${HOME}/.opt"?
3.2 解析參數(shù)
跳過(guò)輔助方法exit_on_err()和usage() ,我們直接看main()。這個(gè)直接用系統(tǒng)方法getopts解析參數(shù),-h則打印幫助信息并退出,-p則指定默認(rèn)值。
while getopts "hp:" ARGdocase ${ARG} inh)usageexit;;p)SANDBOX_INSTALL_PREFIX=${OPTARG};;esacdone# if not appoint the install local, default is ${HOME}/.optif [[ -z ${SANDBOX_INSTALL_PREFIX} ]]; thenSANDBOX_INSTALL_PREFIX=${DEFAULT_SANDBOX_INSTALL_PREFIX}fi3.3 拷貝文件
接下來(lái)根據(jù)指定的(或者默認(rèn)的)目錄地址創(chuàng)建文件夾,并將lib、module、provider下的文件拷貝到安裝目錄下。
# create install dirmkdir -p ${SANDBOX_INSTALL_LOCAL} \|| exit_on_err 1 "permission denied, create ${SANDBOX_INSTALL_LOCAL} failed."# copy filecp -r ./cfg ${SANDBOX_INSTALL_LOCAL}/ \&& cp -r ./lib ${SANDBOX_INSTALL_LOCAL}/ \&& cp -r ./module ${SANDBOX_INSTALL_LOCAL}/ \&& cp -r ./provider ${SANDBOX_INSTALL_LOCAL}/ \&& mkdir -p ${SANDBOX_INSTALL_LOCAL}/bin \|| exit_on_err 1 "permission denied, copy file failed."3.4 更新sandbox.sh腳本
?
?
# replace sandbox.sh\`s ${SANDBOX_HOME_DIR}cat ./bin/sandbox.sh \| sed "s:typeset SANDBOX_HOME_DIR:typeset SANDBOX_HOME_DIR=${SANDBOX_INSTALL_LOCAL}:g" \> ${SANDBOX_INSTALL_LOCAL}/bin/sandbox.sh \&& chmod +x ${SANDBOX_INSTALL_LOCAL}/bin/sandbox.sh \|| exit_on_err 1 "permission denied, replace ${SANDBOX_INSTALL_LOCAL}/bin/sandbox.sh failed."3.5 輸出結(jié)果
最后保存sandbox版本信息,并打印輸出sandbox相關(guān)信息:VERSION、PATH和安裝sandbox成功的信息,也就是前面說(shuō)的判斷成功的信息。
# got sandbox's version local SANDBOX_VERSION=$(cat ${SANDBOX_INSTALL_LOCAL}/cfg/version)echo "VERSION=${SANDBOX_VERSION}" echo "PATH=${SANDBOX_INSTALL_LOCAL}" echo "install sandbox successful."二、快速上手
安裝好sandbox后就可以使用了,使用方法也很簡(jiǎn)單,有兩種執(zhí)行方式:ATTACH和AGENT兩種方式。前者將sandbox attach到指定java進(jìn)程上;后者在啟動(dòng)java虛擬機(jī)的時(shí)候直接指定參數(shù)。熟悉java agent的朋友應(yīng)該知道agent的agentmain和premain兩種方式,這里咱們暫時(shí)留個(gè)伏筆。就筆者個(gè)人來(lái)說(shuō)主要接觸ATTACH方式,在java程序啟動(dòng)后動(dòng)態(tài)加載并改變程序行為。
2.1 ATTACH方式啟動(dòng)
不用重啟目標(biāo)程序,直接attach上去執(zhí)行操作。通過(guò)ps命令獲得目標(biāo)程序的進(jìn)程ID(例子中假設(shè)為47625),則執(zhí)行命令:
# 假設(shè)目標(biāo)JVM進(jìn)程號(hào)為'47625' ./sandbox.sh -p 47625結(jié)果輸出如下信息表明啟動(dòng)成功:
2.2 AGENT方式啟動(dòng)
如果ATTACH方式啟動(dòng)會(huì)影響性能,因?yàn)楫吘辜虞dsandbox需要額外的開(kāi)銷,則可以在程序啟動(dòng)時(shí)添加JVM參數(shù)啟動(dòng):
-javaagent:/Path_to_Install_Directory/sandbox/lib/sandbox-agent.jar/Path_to_Install_Directory是sandbox的安裝目錄。
2.3 實(shí)操(wiki例子:修復(fù)一個(gè)損壞了的鐘)
官方文檔:https://github.com/alibaba/jvm-sandbox/wiki/FIRST-MODULE
2.3.1 創(chuàng)建Clock類
作為實(shí)驗(yàn)對(duì)象的Clock類會(huì)循環(huán)拋出IllegalStateException異常,實(shí)驗(yàn)?zāi)康木褪峭ㄟ^(guò)一個(gè)用戶自定義的module對(duì)該運(yùn)行中的Clock進(jìn)行熱修復(fù),使得程序不再拋出IllegalStateException。官方例子代碼如下:
package com.taobao.demo;/*** 報(bào)時(shí)的鐘*/ public class Clock {// 日期格式化private final java.text.SimpleDateFormat clockDateFormat= new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/*** 狀態(tài)檢查*/final void checkState() {throw new IllegalStateException("STATE ERROR!");}/*** 獲取當(dāng)前時(shí)間** @return 當(dāng)前時(shí)間*/final java.util.Date now() {return new java.util.Date();}/*** 報(bào)告時(shí)間** @return 報(bào)告時(shí)間*/final String report() {checkState();return clockDateFormat.format(now());}/*** 循環(huán)播報(bào)時(shí)間*/final void loopReport() throws InterruptedException {while (true) {try {System.out.println(report());} catch (Throwable cause) {cause.printStackTrace();}Thread.sleep(1000);}}public static void main(String... args) throws InterruptedException {new Clock().loopReport();}}編譯運(yùn)行后程序滾動(dòng)拋出如下異常:
java.lang.IllegalStateException: STATE ERROR!at com.taobao.demo.Clock.checkState(Clock.java:16)at com.taobao.demo.Clock.report(Clock.java:34)at com.taobao.demo.Clock.loopReport(Clock.java:44)at com.taobao.demo.Clock.main(Clock.java:53) java.lang.IllegalStateException: STATE ERROR!at com.taobao.demo.Clock.checkState(Clock.java:16)at com.taobao.demo.Clock.report(Clock.java:34)at com.taobao.demo.Clock.loopReport(Clock.java:44)at com.taobao.demo.Clock.main(Clock.java:53) java.lang.IllegalStateException: STATE ERROR!at com.taobao.demo.Clock.checkState(Clock.java:16)at com.taobao.demo.Clock.report(Clock.java:34)at com.taobao.demo.Clock.loopReport(Clock.java:44)at com.taobao.demo.Clock.main(Clock.java:53)2.3.2 創(chuàng)建修復(fù)Clock的模塊(module)
創(chuàng)建一個(gè)Java工程clock-tinker,并且將parent指向sandbox-module-starter:
<parent><groupId>com.alibaba.jvm.sandbox</groupId><artifactId>sandbox-module-starter</artifactId><version>1.2.2</version></parent>筆者由于在github上下載了sandbox的源代碼,所以直接在以sandbox-module-starter為parent的工程sandbox-mgr-module中創(chuàng)建類BrokenClockTinkerModule:
package com.alibaba.jvm.sandbox.demo;import com.alibaba.jvm.sandbox.api.Information; import com.alibaba.jvm.sandbox.api.Module; import com.alibaba.jvm.sandbox.api.ProcessController; import com.alibaba.jvm.sandbox.api.annotation.Command; import com.alibaba.jvm.sandbox.api.listener.ext.Advice; import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; import org.kohsuke.MetaInfServices;import javax.annotation.Resource;@MetaInfServices(Module.class) @Information(id = "broken-clock-tinker") public class BrokenClockTinkerModule implements Module {@Resourceprivate ModuleEventWatcher moduleEventWatcher;@Command("repairCheckState")public void repairCheckState() {new EventWatchBuilder(moduleEventWatcher).onClass("com.taobao.demo.Clock").onBehavior("checkState").onWatch(new AdviceListener() {/*** 攔截{@code com.taobao.demo.Clock#checkState()}方法,當(dāng)這個(gè)方法拋出異常時(shí)將會(huì)被* AdviceListener#afterThrowing()所攔截*/@Overrideprotected void afterThrowing(Advice advice) throws Throwable {// 在此,你可以通過(guò)ProcessController來(lái)改變?cè)蟹椒ǖ膱?zhí)行流程// 這里的代碼意義是:改變?cè)椒⊕伋霎惓5男袨?#xff0c;變更為立即返回;void返回值用null表示ProcessController.returnImmediately(null);}});}}代碼中的注解和代碼含義大家先不用在意,能猜透哪些算哪些,接下來(lái)我們要把module代碼部署成可用的module。
2.3.3 部署模塊
部署模塊就是把剛才編寫的BrokenClockTinkerModule類打包成jar包,然后復(fù)制該jar包到sandbox安裝目錄下module/下。首先在工程pom文件所在目錄執(zhí)行命令:
mvn clean package然后將打包的sandbox-mgr-module.jar(筆者是直接在sandbox-mgr-module工程中添加的BrokenClockTinkerModule,具體jar包名稱根據(jù)pom配置定)文件復(fù)制到sandbox安裝目錄下的module目錄下。
cp target/sandbox-mgr-module.jar /Path_to_Install_Dir/sandbox/module/sandbox-mgr-module.jar2.3.4 啟動(dòng)sandbox
現(xiàn)在有了實(shí)驗(yàn)對(duì)象Clock,也部署了module,接下來(lái)啟動(dòng)sandbox(2.1部分ATTACH方式啟動(dòng))。
./sandbox.sh -p 47625當(dāng)看到2.1部分所述的信息時(shí)表示掛載成功,可以進(jìn)一步通過(guò)命令驗(yàn)證編寫的模塊正常加載:
./sandbox.sh -p 47625 -l2.3.5 執(zhí)行修復(fù)
module啟動(dòng)后,執(zhí)行下面命令調(diào)用模塊方法進(jìn)行修復(fù):
./sandbox.sh -p 47625 -d 'broken-clock-tinker/repairCheckState'該命令執(zhí)行broken-clock-tinker模塊下repairCheckState方法,執(zhí)行后之前的Clock程序輸出變?yōu)?#xff1a;
java.lang.IllegalStateException: STATE ERROR!at com.example.demo.jvmsandbox.Clock.checkState(Clock.java:12)at com.example.demo.jvmsandbox.Clock.report(Clock.java:30)at com.example.demo.jvmsandbox.Clock.loopReport(Clock.java:40)at com.example.demo.jvmsandbox.Clock.main(Clock.java:49) java.lang.IllegalStateException: STATE ERROR!at com.example.demo.jvmsandbox.Clock.checkState(Clock.java:12)at com.example.demo.jvmsandbox.Clock.report(Clock.java:30)at com.example.demo.jvmsandbox.Clock.loopReport(Clock.java:40)at com.example.demo.jvmsandbox.Clock.main(Clock.java:49) 2019-12-17 18:37:07 2019-12-17 18:37:08 2019-12-17 18:37:09 2019-12-17 18:37:10 2019-12-17 18:37:11這口破損的鐘被修復(fù)了!!!
總結(jié)
以上是生活随笔為你收集整理的AOP—JVM SandBox—快速上手的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: AOP—JVM SandBox—底层原理
- 下一篇: 数据库性能优化—分库分表