前言
以往來看,注解的屬性值一般都是“硬編碼”隆敢。但最近在開發(fā)過程中遇到了需要根據(jù)運(yùn)行環(huán)境來設(shè)置 Retention 為 RUNTIME (運(yùn)行期保留)
的注解屬性值的需求发皿。舉個(gè)例子:
@Table(name="t1")
public class Test {
private String id;
...
}
對于上述類 Test
,其上有一個(gè)注解 @Table
拂蝎,需求是這樣的: 在測試環(huán)境 name 值為"t1"穴墅,在其他環(huán)境 name 值為"t2"。
實(shí)現(xiàn)方法
知識點(diǎn):
- 保留策略為
RUNTIME
的注解在運(yùn)行期是保留的温自。 - 出于某些技術(shù)原因玄货,Java 虛擬機(jī)使用的“真實(shí)”注釋類的實(shí)例是動(dòng)態(tài)代理的實(shí)例。
- Java 注解有一個(gè)名為
memberValues
的私有Map悼泌,其中存儲(chǔ)了屬性名稱和屬性值的k-v
對松捉。
基于上述知識點(diǎn),可以通過反射來訪問實(shí)例馆里,然后用給定的新值替換現(xiàn)有值隘世。
相關(guān)的類:
-
Proxy JDK 動(dòng)態(tài)代理大佬
可通過其getInvocationHandler
方法獲取注解的代理實(shí)例 -
InvocationHandler 調(diào)用處理器鸠踪,每一個(gè)被代理的實(shí)例都有一個(gè)調(diào)用處理器
通過反射獲取被代理類的實(shí)例的屬性值
示例代碼:
// 根據(jù)運(yùn)行環(huán)境獲取表名
String tableName = getTable();
// 獲取 Test 上的注解
Table annoTable = Test.class.getAnnotation(Table.class);
if (annoTable == null) {
throw new RuntimeException("please add @Table for Test");
}
// 獲取代理處理器
InvocationHandler invocationHandler = Proxy.getInvocationHandler(annoTable);
// 過去私有 memberValues 屬性
Field f = invocationHandler.getClass().getDeclaredField("memberValues");
f.setAccessible(true);
// 獲取實(shí)例的屬性map
Map<String, Object> memberValues = (Map<String, Object>) f.get(invocationHandler);
// 修改屬性值
memberValues.put("name", tableName);