一個工作中碰到的小坑
阿新 • • 發佈:2021-06-29
記錄一個小坑,開發壓測平臺的時候碰到的。
背景:現在在開發壓測平臺,抽象類一些常用攔截器作為 starter ,供所有 module 使用(目前我們有7個) 。starter 中使用的一些 entity, 使用了 Threadlocal ,用於儲存使用者資訊和部門資訊
問題:在 module 依賴了 starter 後,讀不到儲存在 Threadlocal 裡的使用者資訊,如 roleID,businessName。
過程: 攔截器和業務程式碼裡都加了以下列印 ThreadlocalMap 的程式碼來看看原因。
最後 double check 了一下,因為定義儲存在 Threadlocal 裡的 entity 類,存在不同的報名,被編譯器認為是兩個不同的類,所以是取不到的,破案。
這個和列印 Threadlocal 的程式碼沒什麼關係,不過學習到了很多 Threadlocal 的知識,學習一下。
記錄下來,作為警示。
以下是程式碼:
/**
* 我是列印ThreadLocalMap的分割線
*
*/
try {
//獲取當前執行緒物件
Thread thread = Thread.currentThread();
//獲取Thread中的threadLocals物件
Field threadLocals = Thread.class.getDeclaredField("threadLocals");
threadLocals.setAccessible(true);
//ThreadLocalMap是ThreadLocal中的一個內部類,並且訪問許可權是default
// 這裡獲取的是ThreadLocal.ThreadLocalMap
Object threadLocalMap = threadLocals.get(thread);
//這裡要這樣獲取ThreadLocal.ThreadLocalMap
Class threadLocalMapClazz = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
//獲取ThreadLocalMap中的Entry物件
Field tableField = threadLocalMapClazz.getDeclaredField("table");
tableField.setAccessible(true);
//獲取ThreadLocalMap中的Entry
Object[] objects = (Object[]) tableField.get(threadLocalMap);
//獲取ThreadLocalMap中的Entry
Class entryClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap$Entry");
//獲取ThreadLocalMap中的Entry中的value欄位
Field entryValueField = entryClass.getDeclaredField("value");
entryValueField.setAccessible(true);
//Entry繼承了WeakReference,WeakReference繼承了Reference
Field referEnceField = Reference.class.getDeclaredField("referent");
referEnceField.setAccessible(true);
Arrays.stream(objects).filter(obj -> obj != null).forEach((obj) -> {
try {
Object value = entryValueField.get(obj);
if (value != null) {
if (value instanceof Reference) {
Reference ref = (Reference) value;
log.info(ref.getClass().getName() + "------>" + ref.get());
} else {
log.info("------>" + value.getClass());
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
/**
* 我是列印ThreadLocalMap的結束
*/