Java反射動態修改註解的值__Java反射

來源:互聯網
上載者:User

先來看看通常情況下,我們通過反射擷取註解的值的情境:

那麼現在我們定義一個 @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);    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.