最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

@ConfigurationProperties注解原理與實(shí)踐方式

 更新時(shí)間:2026年06月03日 09:24:47   作者:小大宇  
這段文章詳細(xì)介紹了@ConfigurationProperties在SpringBoot中的使用方法,并探討了其源碼實(shí)現(xiàn)原理,進(jìn)而引導(dǎo)讀者自己實(shí)現(xiàn)類似功能,涵蓋配置文件解析、Bean生命周期管理等內(nèi)容,同時(shí)強(qiáng)調(diào)了通過學(xué)習(xí)SpringBoot源碼來實(shí)現(xiàn)自定義功能的重要性

一、@ConfigurationProperties 基本使用

在 SpringBoot 中,當(dāng)想需要獲取到配置文件數(shù)據(jù)時(shí),除了可以用 Spring 自帶的 @Value 注解外,SpringBoot 還提供了一種更加方便的方式:@ConfigurationProperties。只要在 Bean 上添加上了這個(gè)注解,指定好配置文件的前綴,那么對(duì)應(yīng)的配置文件數(shù)據(jù)就會(huì)自動(dòng)填充到 Bean 中。

比如在application.properties文件中有如下配置文件

config.username=jay.zhou
config.password=3333

那么按照如下注解配置,SpringBoot項(xiàng)目中使用@ConfigurationProperties的Bean,它的username與password就會(huì)被自動(dòng)注入值了。

就像下面展示的那樣

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "config")
public class TestBean{
    private String username;
    private String password;
}

二、@ConfigurationProperties 源碼的探索及啟發(fā)

SpringBoot為什么能夠獲取到它的值呢?如果讓我從無到有設(shè)計(jì),我應(yīng)該怎么設(shè)計(jì)呢?

首先通過源碼發(fā)現(xiàn),SpringBoot主要幫助我們做了兩件事情。

  • 第一件事情就是獲取到使用@ConfigurationProperties的類。
  • 第二件事就是解析配置文件,并把對(duì)應(yīng)的值設(shè)置到我們的Bean中。

按照源碼提供的實(shí)現(xiàn)思路,其核心就是對(duì)Bean的聲明周期的管理。主要涉及一個(gè)叫做 BeanPostProcessor 的接口,可以在Bean初始化的時(shí)候,我們做一些文章。

下面的兩個(gè)方法,很簡(jiǎn)單,大致意思就是,在Spring的Bean初始化之前與之后執(zhí)行。

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

好了,作為程序員,看了半天源碼,扯了半天淡,不如自己實(shí)現(xiàn)一個(gè)類似的效果來的實(shí)在。

三、代碼

第一步,定義自己的注解。這個(gè)注解最后實(shí)現(xiàn)的功能希望與@ConfigurationProperties 類似。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
    /**
     * 配置屬性 的前綴
     */
    String prefix();
}

第二步,定義配置測(cè)試實(shí)體。

用上了我們剛才定義的@Config注解,并指明其prefix屬性的值為 " default "

import lombok.Data;
import org.springframework.stereotype.Component;
@Config(prefix = "default")
@Component
@Data
public class TestDataSource {
    private String username;
    private String password;
    private int maxActiveCount;
}

第三步,編寫我們的自己的配置文件。為了便于操作(實(shí)際上其它的我不會(huì)解析),使用properties這種文件類型。

我們的目標(biāo)就是把 " default." 后面的對(duì)應(yīng)的字段,注入到上面的TestDataSource里面。

config.properties

default.username = root
default.password = 3333
default.maxActiveCount = 10
default.maxActiveCount2 = 10

第四步,編寫處理邏輯。

(1)獲取使用了我們自定義注解@Config的類

(2)解析配置文件,并將對(duì)應(yīng)的值使用反射技術(shù),注入到Bean中。

下面是最主要的處理代碼。實(shí)現(xiàn)BeanPostProcessor接口的方法,檢查每一個(gè)初始化成功的Bean,如果使用了我們的自定義注解,那么就把從配置文件中解析出來的數(shù)據(jù),使用反射技術(shù)注入進(jìn)去。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
@Component
public class ConfigPostProcess implements BeanPostProcessor {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigPostProcess.class);
    private static final String FILE_NAME = "config.properties";
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //獲取使用了我們自定義注解@Config的類
        Config configAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), Config.class);
        //如果這個(gè)對(duì)象使用了此注解
        if (configAnnotation != null) {
            LOGGER.info("當(dāng)前操作的類:{}", beanName);
            //解析配置文件,并將解析結(jié)果放入Map中
            Map<String, String> configProperties = getConfigPropertiesFromFile(configAnnotation);
            //將對(duì)應(yīng)的值,使用反射技術(shù),注入到這個(gè)bean中
            bindBeanValue(bean, configProperties);
        }
        return bean;
    }
  ...
}

四、實(shí)現(xiàn)效果

SpringBoot很多都是通過注解來實(shí)現(xiàn)功能的。只要我們能夠?qū)W習(xí)其源碼實(shí)現(xiàn)思路,我們也可以做出很多很多類似的功能。盡管我們的代碼健壯性做不到跟大佬一樣,但是在特定業(yè)務(wù)場(chǎng)景下,比如對(duì)某個(gè)特別重要的單例Bean進(jìn)行操作,或者為某一類特定的接口實(shí)現(xiàn),做一些特定的處理,可以考慮這種技術(shù)。

另外,對(duì)于反射的使用,在SpringBoot框架學(xué)習(xí)過程中也是一個(gè)非常重要的部分。

只有經(jīng)常手敲代碼,才能孰能生巧,切忌紙上談兵。只有切實(shí)自己實(shí)現(xiàn)了特定功能,回頭查看SpringBoot替我們做的事情,才能做到心中有數(shù),否則被新手程序員問一句 " 為什么要這么配置 " 就啞口無言,實(shí)在是很尷尬。

點(diǎn)擊動(dòng)圖后,效果可以更加清楚哦?。。?/span>

附錄私有方法

   /**
     * 將對(duì)應(yīng)的值,使用反射技術(shù),注入到這個(gè)bean中
     */
    private void bindBeanValue(Object bean, Map<String, String> configProperties) {
        if (configProperties.size() > 0) {
            configProperties.forEach((key, value) -> {
                setFieldValueByFieldName(key, bean, value);
            });
        }
    }
    /**
     *  從配置文件中讀取配置好的鍵值對(duì),并放入到Map中
     */
    private Map<String, String> getConfigPropertiesFromFile(Config configAnnotation) {
        //get prefix from annotation
        String prefix = configAnnotation.prefix();
        //read value from resource file
        Properties properties = getClassNameFromResource(FILE_NAME);
        Map<String, String> configProperties = new HashMap<>();
        Set<String> keys = properties.stringPropertyNames();
        List<String> keyList = new ArrayList<>(keys);
        for (String key : keyList) {
            if (key.startsWith(prefix)) {
                //default.password ==> password
                String realKey = key.substring(key.indexOf(prefix) + prefix.length() + 1);
                String value = properties.getProperty(key);
                configProperties.put(realKey, value);
            }
        }
        return configProperties;
    }
    /**
     * 讀取配置文件,返回一個(gè)流對(duì)象
     */
    private Properties getClassNameFromResource(String fileName) {
        Properties properties = new Properties();
        ClassLoader classLoader = ConfigPostProcess.class.getClassLoader();
        InputStream inputStream = classLoader.getResourceAsStream(fileName);
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return properties;
    }
    /**
     * 為指定字段使用反射技術(shù)設(shè)值(只支持String 與 int 類型)
     */
    private void setFieldValueByFieldName(String fieldName, Object object, String value) {
        try {
            Class c = object.getClass();
            if (checkFieldExists(fieldName, c)) {
                Field f = c.getDeclaredField(fieldName);
                f.setAccessible(true);
                //如果不是String,那么就是int。其它類型不支持
                if(f.getType().equals(String.class)){
                    f.set(object, value);
                }else{
                    int number = Integer.valueOf(value);
                    f.set(object, number);
                }
            }
        } catch (Exception e) {
            LOGGER.error("設(shè)置" + fieldName + "出錯(cuò)");
        }
    }
    /**
     * 檢查這個(gè)Bean是否有配置文件中配置的字段
     * 沒有就不設(shè)置了
     */
    private boolean checkFieldExists(String fieldName, Class c) {
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().equals(fieldName)) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java Swing實(shí)現(xiàn)選項(xiàng)卡功能(JTabbedPane)實(shí)例代碼

    java Swing實(shí)現(xiàn)選項(xiàng)卡功能(JTabbedPane)實(shí)例代碼

    這篇文章主要介紹了java Swing實(shí)現(xiàn)選項(xiàng)卡功能(JTabbedPane)實(shí)例代碼的相關(guān)資料,學(xué)習(xí)java 基礎(chǔ)的朋友可以參考下這個(gè)簡(jiǎn)單示例,需要的朋友可以參考下
    2016-11-11
  • Java注解Annotaton詳解

    Java注解Annotaton詳解

    Java 注解(Annotation)又稱 Java 標(biāo)注,是 JDK5.0 引入的一種注釋機(jī)制,文中給大家介紹了三種基本的Annotaton,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-05-05
  • Springboot如何優(yōu)雅的關(guān)閉應(yīng)用

    Springboot如何優(yōu)雅的關(guān)閉應(yīng)用

    這篇文章主要介紹了Springboot如何優(yōu)雅的關(guān)閉應(yīng)用問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Spring Cloud微服務(wù)之間調(diào)用Dubbo的詳細(xì)過程

    Spring Cloud微服務(wù)之間調(diào)用Dubbo的詳細(xì)過程

    SpringCloudAlibabaDubbo是阿里巴巴開源的Dubbo與SpringCloud的深度集成方案,本文介紹Spring Cloud微服務(wù)之間調(diào)用Dubbo的詳細(xì)過程,感興趣的朋友跟隨小編一起看看吧
    2026-02-02
  • java實(shí)現(xiàn)微信搶紅包算法

    java實(shí)現(xiàn)微信搶紅包算法

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信搶紅包算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • 解決idea services窗口不見的一種特殊情況(小白采坑系列)

    解決idea services窗口不見的一種特殊情況(小白采坑系列)

    這篇文章主要介紹了解決idea services窗口不見的一種特殊情況(小白采坑系列),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解

    SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解

    這篇文章主要介紹了SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • IDEA設(shè)置背景為自定義照片的操作方法

    IDEA設(shè)置背景為自定義照片的操作方法

    這篇文章主要介紹了IDEA設(shè)置背景為自定義照片,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • 用Java集合中的Collections.sort方法如何對(duì)list排序(兩種方法)

    用Java集合中的Collections.sort方法如何對(duì)list排序(兩種方法)

    本文通過兩種方法給大家介紹java集合中的Collections.sort方法對(duì)list排序,第一種方式是list中的對(duì)象實(shí)現(xiàn)Comparable接口,第二種方法是根據(jù)Collections.sort重載方法實(shí)現(xiàn),對(duì)collections.sort方法感興趣的朋友一起學(xué)習(xí)吧
    2015-10-10
  • java基礎(chǔ)學(xué)習(xí)筆記之泛型

    java基礎(chǔ)學(xué)習(xí)筆記之泛型

    所謂泛型,就是變量類型的參數(shù)化。泛型是JDK1.5中一個(gè)最重要的特征。通過引入泛型,我們將獲得編譯時(shí)類型的安全和運(yùn)行時(shí)更小的拋出ClassCastException的可能。在JDK1.5中,你可以聲明一個(gè)集合將接收/返回的對(duì)象的類型。
    2016-02-02

最新評(píng)論

板桥市| 东阿县| 余庆县| 仙居县| 大名县| 林西县| 祁东县| 白玉县| 县级市| 九龙坡区| 梅河口市| 辰溪县| 崇阳县| 江西省| 永修县| 武乡县| 仪征市| 琼中| 茂名市| 冕宁县| 云浮市| 上饶市| 高碑店市| 兴义市| 洪洞县| 炉霍县| 卢龙县| 镇平县| 湾仔区| 河南省| 沈阳市| 谷城县| 弥勒县| 玛沁县| 井冈山市| 工布江达县| 临泉县| 玉林市| 康定县| 深水埗区| 南通市|