Java反射動態修改注解的值


先來看看通常情況下,我們通過反射獲取注解的值的場景:

那么現在我們定義一個 @Foo 注解,它有一個類型為 String 的 value 屬性,該注解應用再Field上:

/**
 * @Author 落葉飛翔的蝸牛
 * @Date 2018/3/11
 * @Description
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Foo {
    String value();
}

再定義一個普通的Java對象 Bar,它有一個私有的String屬性 value,並為它設置屬性值為"test.annotation.value" 的 @Foo 注解

/**
 * @Author 落葉飛翔我蝸牛
 * @Date 2018/3/11
 * @Description
 */
public class Bar {
    @Foo("test.annotation.value")
    private String value;
}

正常的獲取注解屬性值的場景:

/**
 * @Author 落葉飛翔的蝸牛
 * @Date 2018/3/10
 * @Description
 */
@RunWith(SpringRunner.class)
public class ReflectionAnnotationTest {
 
    @Test
    public void test() throws NoSuchFieldException, IllegalAccessException {
        //獲取Bar實例
        Bar bar = new Bar();
        //獲取Bar的val字段
        Field field = bar.getClass().getDeclaredField("value");
        //獲取val字段上的Foo注解實例
        Foo foo = field.getAnnotation(Foo.class);
        //獲取Foo注解實例的 value 屬性值
        String value =  foo.value();
        //打印該值
        System.out.println("修改之前的注解值:" + value);
 
    }
}

  我們在上面的String value = foo.value(); 處下斷點,我們跑一下可以發現當前棧中有這么幾個變量,不過其中有一點很特別:foo,其實是個Proxy實例。

 

看到foo棧中的屬性h是一個AnnotationInvocationHandler類型的對象。h對象中包含一個memberValues對象,里面裝着key就是我們自定義注解的屬性,value就是我賦的值。我們看一下AnnotationInvocationHandler類的源碼:

class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    private static final long serialVersionUID = 6182022883658399397L;
    private final Class<? extends Annotation> type;
    private final Map<String, Object> memberValues;

可以發現memberValues對象是private final修飾的。所以我們可以通過反射修改memberValues的訪問權限,來打到修改memberValues值的目的。

所以動態修改注解的值的方法為:通過反射得到foo的代理對象,然后得到代理對象的memberValues屬性,修改訪問權限,更新注解的value屬性值。修改后的代碼如下:

/**
 * @Author 落葉飛翔的蝸牛
 * @Date 2018/3/10
 * @Description
 */
@RunWith(SpringRunner.class)
public class ReflectionAnnotationTest {
 
    @Test
    public void test() throws NoSuchFieldException, IllegalAccessException {
        //獲取Bar實例
        Bar bar = new Bar();
        //獲取Bar的val字段
        Field field = bar.getClass().getDeclaredField("value");
        //獲取val字段上的Foo注解實例
        Foo foo = field.getAnnotation(Foo.class);
        //獲取Foo注解實例的 value 屬性值
        String value =  foo.value();
        //打印該值
        System.out.println("修改之前的注解值:" + value);
 
        System.out.println("------------以下是修改注解的值------------");
 
        //獲取 foo 這個代理實例所持有的 InvocationHandler
        InvocationHandler invocationHandler = Proxy.getInvocationHandler(foo);
        // 獲取 AnnotationInvocationHandler 的 memberValues 字段
        Field declaredField = invocationHandler.getClass().getDeclaredField("memberValues");
        // 因為這個字段事 private final 修飾,所以要打開權限
        declaredField.setAccessible(true);
        // 獲取 memberValues
        Map memberValues = (Map) declaredField.get(invocationHandler);
        // 修改 value 屬性值
        memberValues.put("value", "test.annotation.new.value");
        // 獲取 foo 的 value 屬性值
        String newValue = foo.value();
        System.out.println("修改之后的注解值:" + newValue);
    }
}

版權聲明:本文為CSDN博主「ShiXueTanLang」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/ShiXueTanLang/article/details/79516029


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM