1. 手寫web服務(wù)器:定義@value注解,實現(xiàn)配置自動注入

        共 10560字,需瀏覽 22分鐘

         ·

        2021-06-12 06:33

        前言

        昨天我們定義了Configuration注解和Bean注解,實現(xiàn)了更靈活的類注入,今天我們來看另一個配置注入的注解Value,這個注解也是我們在springboot中經(jīng)常用到的,今天我們就來看下如何通過value注解實現(xiàn)properties配置的自動注入。

        實現(xiàn)過程

        定義properties工具類

        這個工具類的作用主要是解析我們的配置文件,并生成一個配置文件的字典數(shù)據(jù),然后我們可以根據(jù)自己的需要獲取對應(yīng)的配置,這也是我們實現(xiàn)配置自動注入的第一步。

        public class PropertiesUtil {
            private static HashMap<String, PropertiesUtil> configMap = new HashMap();
            private Date loadTime = null;
            private ResourceBundle resourceBundle = null;
            private static final Integer TIME_OUT = 60000;

            private PropertiesUtil(String name) {
                this.loadTime = new Date();

                try {
                    this.resourceBundle = ResourceBundle.getBundle(name);
                } catch (Exception var3) {
                    this.resourceBundle = null;
                }

            }

            public static synchronized PropertiesUtil getInstance() {
                return getInstance("application");
            }

            public static synchronized PropertiesUtil getInstance(String name) {
                PropertiesUtil conf = configMap.get(name);
                if (null == conf) {
                    conf = new PropertiesUtil(name);
                    configMap.put(name, conf);
                }

                if ((new Date()).getTime() - conf.getLoadTime().getTime() > (long)TIME_OUT) {
                    conf = new PropertiesUtil(name);
                    configMap.put(name, conf);
                }

                return conf;
            }

            public String get(String key) {
                try {
                    String value = this.resourceBundle.getString(key);
                    return value;
                } catch (MissingResourceException var3) {
                    return "";
                } catch (NullPointerException var4) {
                    return "";
                }
            }

            public Integer getInt(String key) {
                try {
                    String value = this.resourceBundle.getString(key);
                    return Integer.parseInt(value);
                } catch (MissingResourceException var3) {
                    return null;
                } catch (NullPointerException var4) {
                    return null;
                }
            }

            public boolean getBoolean(String key) {
                try {
                    String value = this.resourceBundle.getString(key);
                    return "true".equals(value);
                } catch (MissingResourceException var3) {
                    return false;
                } catch (NullPointerException var4) {
                    return false;
                }
            }

            public Date getLoadTime() {
                return this.loadTime;
            }

            public static String getPropertiesValue(String name, String key) {
                try {
                    return getInstance(name).get(key);
                } catch (MissingResourceException var3) {
                    return "";
                } catch (NullPointerException var4) {
                    return "";
                }
            }
        }

        定義value注解

        依然是輕車熟路,這里的value()是用來接受我們的配置名稱的。

        @Target(ElementType.FIELD)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Value {
            String value();
        }

        實現(xiàn)配置注入

        在之前的實現(xiàn)基礎(chǔ)上,我們增加了一個配置處理的類,這個類有兩個方法,分別是用于實現(xiàn)單個屬性注入和批量屬性注入:

        public class ConfigurationHandler {
            private static final PropertiesUtil propertiesUtil = PropertiesUtil.getInstance("application");

            /**
             * 初始化value配置信息
             * @param instance
             * @param field
             * @throws IllegalAccessException
             */

            public static void initValueConfig(Object instance, Field field) throws IllegalAccessException {
                Annotation annotation = field.getAnnotation(Value.class);
                if (Objects.nonNull(annotation)) {
                    String propertiesKeyName = ((Value) annotation).value();
                    Class<?> type = field.getType();
                    if (!field.isAccessible()) {
                        field.setAccessible(Boolean.TRUE);
                    }
                    if (Integer.class.equals(type)) {
                        field.setInt(instance, propertiesUtil.getInt(propertiesKeyName));
                    } else if (Boolean.class.equals(type)) {
                        field.setBoolean(instance, propertiesUtil.getBoolean(propertiesKeyName));
                    } else {
                        field.set(instance, propertiesUtil.get(propertiesKeyName));
                    }
                }
            }

            /**
             * 批量初始化value配置
             * @param aClass
             * @param instance
             * @throws IllegalAccessException
             */

            public static void batchInitValueConfig(Class aClass, Object instance) throws IllegalAccessException {
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    initValueConfig(instance, declaredField);
                }

            }
        }

        首先,我們在IoC實例化階段,對各種組件的字段進行掃描,拿出有Value注解的屬性,根據(jù)注解的值獲取對應(yīng)的配置。

        使用效果

        我們在service組件上加入一個屬性,并加上value注解:

        然后在我們的配置文件中增加對應(yīng)的配置:

        運行測試

        運行測試下:

        可以看到,我們的配置已經(jīng)被注入進來了,這樣注入配置,既簡單又方便。當然,相比于SpringValue注解,我們的還是顯得比較低級,因為springvalue注解是支持表達式的,它有一套專門的Spring EL,所以我們看的springvalue是這樣寫的:

        @Value("${syske.boot.server.name}")
        private String serverName;
        // 或者這樣
        @Value("#{syske.boot.server.name}")
        private String serverName;

        好了,今天的內(nèi)容就這么多,我們接下來總結(jié)一下。

        總結(jié)

        注解本質(zhì)上只是一種標記,是為了便于我們通過反射操作類的屬性、方法等資源,實現(xiàn)我們的高級功能。value注解就是獲取配置的一種標記,我們通過在實例化對象后對其字段操作,實現(xiàn)配置的自動注入。

        在我實際測試的時候,我發(fā)現(xiàn)這種配置注入方式,對靜態(tài)變量也是有效的,但是springvalue對靜態(tài)變量是無效的,暫時沒有去看spring的源碼,不知道是實現(xiàn)方式的問題還是EL表達式的鍋。

        原本我以為是因為字段和方法的反射操作都是基于類的實例,所以對于靜態(tài)方法和變量是沒有任何效果的,但是經(jīng)過實測的時候,發(fā)現(xiàn)并非如此,后面再好好研究下。

        下面是項目的開源倉庫,有興趣的小伙伴可以去看看,如果有想法的小伙伴,我真心推薦你自己動個手,自己寫一下,真的感覺不錯:

        https://github.com/Syske/syske-boot
        - END -


        瀏覽 80
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 国产精品成年片在线观看, | 宝贝快在深一点好舒服 | 红桃视频一区二区三区免费观看 | 萍萍的性荡生活 | 黄色91免费版 |