java探針技術II——如何在不依賴 spring 的情況下汛蝙,使用 spring

場景

通常來說烈涮,探針不會引入太重量級的框架,會更多地使用 JDK 原生的接口窖剑。然而最近發(fā)現(xiàn)坚洽,當探針依附在用戶應用中時( Spring 應用),有時難免需要使用反射調(diào)用用戶接口或 Spring 接口西土,而反射調(diào)用需要類實例讶舰,使用 Spring 進行依賴注入的框架中,這個實例必須從 Spring Context 中去取需了。這就造成了一個問題跳昼,如何取到 Spring Context 呢,難道一定要在探針中引入 Sping 框架嗎肋乍?

理論上其實很容易想到——代理鹅颊,那么具體怎么做呢,不多說住拭,直接看代碼挪略。

這里使用的基礎代碼來自 java探針技術I——如何寫一個 java agent

定義 ApplicationContextHolder

首先我們需要一個地方历帚,存放獲取到的 Spring Context 滔岳,以便在后續(xù)的代碼中,隨時可以取用挽牢。

新增 ApplicationContextHolder

public class ApplicationContextHolder {
    public static Object applicationContextObj;
}

記住谱煤,我們已經(jīng)沒有 Spring 了,一切皆對象

添加代理類

使用提供代理功能的類庫禽拔,這里使用到的是 bytebuddy 刘离,還有一些其他的如 cglib 。挑自己順手的就好睹栖,目的是在 Spring 啟動時硫惕,攔截特定的類,獲取 Spring Context 野来。

添加代理類 ContextAdvice

public class ContextAdvice {
    @Advice.OnMethodEnter
    static void enter(@Advice.AllArguments Object[] args) {
        ApplicationContextHolder.applicationContextObj = args[0];
    }
}

語法就不細說了恼除,可以參考官網(wǎng)。這里是定義在進入特定的方法時,將參數(shù)賦值給我們的 ApplicationContextHolder豁辉。

這個代理要綁定到哪里呢令野,根據(jù)經(jīng)驗(寫過),可以從ApplicationContextAware 下手徽级。

Spring 在啟動時會調(diào)用所有 ApplicationContextAware 接口气破,并將 Context 通知到 setApplicationContext方法,其源碼如下

···

public interface ApplicationContextAware extends Aware {

   /**
    * Set the ApplicationContext that this object runs in.
    * Normally this call will be used to initialize the object.
    * <p>Invoked after population of normal bean properties but before an init callback such
    * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
    * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
    * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
    * {@link MessageSourceAware}, if applicable.
    * @param applicationContext the ApplicationContext object to be used by this object
    * @throws ApplicationContextException in case of context initialization errors
    * @throws BeansException if thrown by application context methods
    * @see org.springframework.beans.factory.BeanInitializationException
    */
   void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

官方文檔中還有一句

ApplicationObjectSupport is a convenience base class for application objects, implementing this interface.

雖然文檔中并沒有說明這個類具體是從Spring 的哪個版本開始引入的餐抢,但是根據(jù)一系列谷歌现使,就是蠻久的啦,應該可以兼容到我讀初中時候的 Spring 版本弹澎。朴下。

所以,在探針啟動時苦蒿,我們將該代理類綁定到 ApplicationObjectSupport 類的 setApplicationContext 方法上殴胧。

修改 StartUp

public class StartUp {

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("hello, i'am agent!");

        final ElementMatcher.Junction<NamedElement> springApplicationType = ElementMatchers.nameEndsWith("ApplicationObjectSupport");
        final AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
            
            @Override
            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
                return builder.method(ElementMatchers.named("setApplicationContext"))
                        .intercept(Advice.to(ContextAdvice.class));
            }
        };
        new AgentBuilder.Default()
                .with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
                .type(springApplicationType)
                .transform(transformer)
                .installOn(inst);
    }
}

驗證

為了方便驗證結果,又暗搓搓地使用 spark 暴露了一個 web 接口佩迟,這個接口返回 Spring Context 的所有內(nèi)容团滥。

引入依賴

<dependency>
    <groupId>com.sparkjava</groupId>
    <artifactId>spark-core</artifactId>
    <version>2.8.0</version>
</dependency>

StartUp 類的末尾添加一行

get("/spring", (req, res) -> ApplicationContextHolder.applicationContextObj);

好了,打包报强,編譯灸姊,運行!

Demo 項目啟動完畢之后秉溉,訪問 http://localhost:4567/springspark 默認 4567)力惯,可以看到如下返回信息,表示我們成功獲取到 Spring Context

org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@3d34d211, started on Wed Jul 17 16:09:09 CST 2019

啰嗦幾句

接下來就是怎么使用的問題了召嘶,首先用反射從 Spring Context 中獲取 Bean 父晶,再使用反射調(diào)用這個 Bean 的方法或者屬性∨總之甲喝,對著 API 盲寫代碼,沒有 Spring 铛只,只有 Object埠胖,ClassMethod…..是個體力活淳玩!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末直撤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜕着,更是在濱河造成了極大的恐慌谋竖,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異圈盔,居然都是意外死亡豹芯,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門驱敲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铁蹈,“玉大人,你說我怎么就攤上這事众眨∥漳粒” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵娩梨,是天一觀的道長沿腰。 經(jīng)常有香客問我,道長狈定,這世上最難降的妖魔是什么颂龙? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮纽什,結果婚禮上措嵌,老公的妹妹穿的比我還像新娘。我一直安慰自己芦缰,他們只是感情好企巢,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著让蕾,像睡著了一般浪规。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上探孝,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天笋婿,我揣著相機與錄音,去河邊找鬼再姑。 笑死萌抵,一個胖子當著我的面吹牛找御,可吹牛的內(nèi)容都是我干的元镀。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼霎桅,長吁一口氣:“原來是場噩夢啊……” “哼栖疑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起滔驶,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤遇革,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萝快,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡锻霎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了揪漩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旋恼。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奄容,靈堂內(nèi)的尸體忽然破棺而出冰更,到底是詐尸還是另有隱情,我是刑警寧澤昂勒,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布蜀细,位于F島的核電站,受9級特大地震影響戈盈,放射性物質(zhì)發(fā)生泄漏奠衔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一塘娶、第九天 我趴在偏房一處隱蔽的房頂上張望涣觉。 院中可真熱鬧,春花似錦血柳、人聲如沸官册。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽膝宁。三九已至,卻和暖如春根吁,著一層夾襖步出監(jiān)牢的瞬間员淫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工击敌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留介返,地道東北人。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓沃斤,卻偏偏與公主長得像圣蝎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子衡瓶,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350

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

  • 來源:關于Spring IOC (DI-依賴注入)你需要知道的一切作者:zejian Dao層(AccountDa...
    楊井閱讀 5,329評論 0 27
  • IOC和DI是什么徘公? Spring IOC 的理解,其初始化過程哮针? BeanFactory 和 FactoryBe...
    justlpf閱讀 3,463評論 1 21
  • Spring致力于提供一種方法管理你的業(yè)務對象关面。在大量Java EE的應用中坦袍,隨處可見Spring。今天我將簡單的...
    JAVA架構師的圈子閱讀 1,328評論 0 16
  • 說明:本文主要內(nèi)容來自慕課網(wǎng)等太。配合視頻食用口味更佳捂齐。主要是順著已經(jīng)學習的視頻順序總結一遍,以深化理解和方便日后復習...
    stoneyang94閱讀 849評論 3 5
  • 自從有了你缩抡,我的生活就多了一份牽掛辛燥,也多了一份期待。 你的到來缝其,讓我明確了未來的方向挎塌。努力,也變成了一件有意義的事...
    無夢樓緣緣堂閱讀 146評論 0 1