1. 淺談運(yùn)行時(shí)修改Java注解的值

        共 6266字,需瀏覽 13分鐘

         ·

        2023-11-06 23:18

        這里介紹如何在運(yùn)行時(shí)修改注解的值

        abstract.jpg

        基本原理

        查看JDK中Annotation接口的注釋,說(shuō)明所有注解都擴(kuò)展自Annotation接口。換言之,注解本質(zhì)上就是一個(gè)繼承了Annotation的接口

        package java.lang.annotation;

        /**
         * The common interface extended by all annotation types.
         * ...
         * @author  Josh Bloch
         * @since   1.5
         */

        public interface Annotation {
            ...
        }

        這里,我們先自定義一個(gè)注解@MyLog,同時(shí)定義一個(gè)類UserInfoService來(lái)使用該注解

        /**
         * 自定義注解
         */

        @Target(ElementType.METHOD)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface MyLog {
            String level() default "TRACE";
        }

        ...

        public class UserInfoService {

            @MyLog( level = "DEBUG")
            public void attachById(Integer userId) {
            }

            @MyLog( level = "INFO")
            public void batchDelete(List<Integer> ids) {

            }
        }

        現(xiàn)在我們通過(guò)debug的方式來(lái)查看反射后的注解對(duì)象。由于注解的具體實(shí)現(xiàn)類是利用JDK動(dòng)態(tài)代理生成的。故我們通過(guò)反射獲得的注解對(duì)象,實(shí)際上是運(yùn)行時(shí)生成的動(dòng)態(tài)代理對(duì)象Proxy

        public class RuntimeModifyAnnoTest {
            public static void main(String[] args) throws NoSuchMethodException {
                test1();
            }

            public static void test1() throws NoSuchMethodException {
                // 獲取類的方法
                Method attachByIdMethod = UserInfoService.class.getDeclaredMethod("attachById", Integer.class);
                // 獲取方法的注解
                MyLog attachByIdMyLog = attachByIdMethod.getDeclaredAnnotation( MyLog.class );
                String level = attachByIdMyLog.level();
                System.out.println("Level : " + level);
            }
        }
        figure 1.jpg

        而當(dāng)我們通過(guò)這個(gè)動(dòng)態(tài)代理對(duì)象Proxy訪問(wèn)level屬性值時(shí),其會(huì)通過(guò)調(diào)用 AnnotationInvocationHandler 的invoke方法來(lái)實(shí)現(xiàn)。進(jìn)一步地觀察invoke方法的源碼,不難看出其最終是從memberValues這個(gè)Map中獲取到對(duì)應(yīng)的值

        figure 2.jpg

        實(shí)踐

        現(xiàn)在,我們?nèi)绻谕谶\(yùn)行時(shí)修改注解的屬性值就非常簡(jiǎn)單了。只需先通過(guò)反射獲取注解的代理對(duì)象,然后獲取該代理對(duì)象的InvocationHandler實(shí)例,最后修改AnnotationInvocationHandler實(shí)例的memberValues字段中屬性值即可。下述代碼,嘗試將attachById方法上@MyLog注解的值由DEBUG修改為WARN;而batchDelete方法上@MyLog注解的值則不會(huì)受到影響

        /**
         * 動(dòng)態(tài)修改注解值
         */

        public class RuntimeModifyAnnoTest {

            public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
                test2();
            }

            public static void test2() throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
                // 獲取類的方法
                Method attachByIdMethod = UserInfoService.class.getDeclaredMethod("attachById", Integer.class);
                // 獲取方法的注解
                MyLog attachByIdMyLog = attachByIdMethod.getDeclaredAnnotation( MyLog.class );
                // 獲取注解level屬性的值
                String level = attachByIdMyLog.level();
                System.out.println("attachById方法 @MyLog注解 level屬性值: " + level);

                //獲取該代理對(duì)象的InvocationHandler調(diào)用處理器實(shí)例
                InvocationHandler invocationHandler = Proxy.getInvocationHandler( attachByIdMyLog );
                // 獲取AnnotationInvocationHandler類的的私有字段 memberValues
                Field memberValuesField = invocationHandler.getClass().getDeclaredField("memberValues");
                // 因?yàn)?nbsp;memberValues 字段為private,故需設(shè)置為可訪問(wèn)
                memberValuesField.setAccessible(true);
                // 獲取 memberValues 字段的值
                Map<String, Object> memberValues = (Map<String, Object>) memberValuesField.get(invocationHandler);

                // 修改注解屬性為level的值
                memberValues.put("level""WARN");
                // 獲取注解level屬性的值
                level = attachByIdMyLog.level();
                System.out.println("attachById方法 @MyLog注解 level屬性值: " + level);

                // 獲取類的方法
                Method batchDeleteMethod = UserInfoService.class.getDeclaredMethod("batchDelete", List.class);
                // 獲取方法的注解
                MyLog batchDeleteMyLog = batchDeleteMethod.getDeclaredAnnotation( MyLog.class );
                // 獲取注解level屬性的值
                level = batchDeleteMyLog.level();
                System.out.println("batchDelete方法 @MyLog注解 level屬性值: " + level);
            }
        }

        效果如下所示

        figure 3.jpg

        瀏覽 182
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 成人免费 做爱视频 | 1v1被强行糟蹋h | 免费看男女交性视频 | 男女操逼高清网 | 受被很多人c屁股在外面被c |