在開發過程經常有同學問:“我這個配置更新提交了,怎么樣知道項目中是否已經更新使用新值?” 常用的方法是添加日志打印該值判斷是否更新。今天我們用Arthas來實現項目中配置值實時讀取。
Arthas 簡介
Arthas 是Alibaba開源的Java診斷工具。使用 Arthas 可以很方便幫助我們排查線上問題。下面簡單介紹幾個常用的命令以及使用的場景。
- jad 命令反編譯指定已加載類的源碼。在代碼修改了不生效,懷疑代碼沒有部署時可以通過該命令查看源碼。
- thread 命令查看當前線程信息,線程的堆棧。線程池線程爆滿時用該命令查看阻塞線程;CPU使用率過高用該命令查看占用CPU最高的線程。
- jvm 命令查看當前JVM信息。查看使用什么垃圾回收算法、線程數和阻塞線程數等。
- watch 命令方法執行數據觀測。觀察方法入參和返回值,或者報錯信息等。
- trace 命令方法內部調用路徑,並輸出方法路徑上的每個節點上耗時。查看方法內部調用所有的接口和每個接口對應的耗時,這個可以很好的掌控接口性能質量。
- tt 命令記錄下指定方法每次調用的入參和返回信息,並能對這些不同的時間下調用進行觀測。需要重現某個問題時,需要前端同學配合點擊,用這個命令可以代替前端同學,回放之前的請求。
- getstatic 命令可以查看類的靜態屬性。
- ognl 命令可以查看類的靜態屬性,並且可以做很多不可以描述的事情!
上面的命令是作為開發經常使用到的,具體怎么樣使用Arthas請看官網。
OGNL竊取SpringContext屬性
假設大家都知道 SpringBoot 讀取配置之后存在 ConfigurableApplicationContext 的 environment 中。如果有不知道的,可以在 PropertySourceBootstrapConfiguration#initialize 方法里打個斷點debug調試一波😏。下面用一個例子操作一波。
步驟一
application.properties文件中添加 author=Greiz 鍵值對。
步驟二
想辦法拿到項目中 ApplicationContext 對象。ognl只獲取靜態屬性,所以我們一般需要查找項目中是否存在靜態的ApplicationContext對象。這里面我就自己創建了一個類來提供靜態的ApplicationContext。
package com.greiz.demo.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ConfigHandler implements InitializingBean, ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(applicationContext.getEnvironment().getProperty("author"));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ConfigHandler.applicationContext = applicationContext;
}
}
這種方式是不是到處可見。如果用Dubbo的,Dubbo框架里com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory 持有靜態的 ApplicationContext 對象。
步驟三
使用ognl獲取靜態 ApplicationContext 屬性。
ognl '#context=@com.greiz.demo.config.ConfigHandler@applicationContext,#context.getEnvironment().getProperty("author")'
逗號之前是獲取 ApplicationContext 對象並賦值給 context。逗號后面的獲取 Environment 對象中的屬性。這個 "author" 屬性就是application.properties 配置的,也可以是遠程的配置文件。
對應的結果

其實只要獲取到ApplicationContext 對象,我們就可以對Spring容器為所欲為了,比如下面不知恥辱的行為:
@Component
public class Greiz {
@Value("${userName}")
private String name;
@Value("${userAge}")
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}

可以獲取Spring容器的所有bean,然后調用對應的方法。
總結
熟悉Arthas 工具常用命令;了解配置最終所保存的對象;提供靜態屬性的 ApplicationContext 對象;ognl獲取Spring容器鑰匙ApplicationContext,然后做你們想做的事。
