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

Spring—@Value在static中引用方式

 更新時(shí)間:2023年09月21日 10:07:01   作者:花無名v5  
這篇文章主要介紹了Spring—@Value在static中引用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@Value注解

spring在讀取yml、properties等文件中的配置時(shí),可直接使用@Value注解。

而且@Value除了支持String,int等類型的數(shù)據(jù),還支持?jǐn)?shù)組、Map、bean多種類型數(shù)據(jù)注入,應(yīng)用起來非常方便。

不過在使用這個(gè)注解的過程中也有需要注意的點(diǎn)。

其中一點(diǎn)就是靜態(tài)屬性的注入時(shí)機(jī),如果使用方法不當(dāng),靜態(tài)屬性無法完成屬性注入;第二點(diǎn)是需要用什么方式,才可以在在靜態(tài)方法、靜態(tài)代碼塊中獲取配置的屬性信息。

本文主要是對(duì)@Value在這兩種情況下的使用進(jìn)行說明,同時(shí)簡(jiǎn)單講解一下@Value注入的原理。

代碼加載順序

在進(jìn)入@Value使用介紹之前,先說下對(duì)于包含靜態(tài)方法、靜態(tài)代碼塊、@PostConstruct方法、默認(rèn)構(gòu)造方法的代碼執(zhí)行順序是什么樣的。

static修飾的靜態(tài)方法、代碼塊、靜態(tài)屬性,都是在類加載的時(shí)候就進(jìn)行加載,并且靜態(tài)代碼塊是會(huì)主動(dòng)執(zhí)行,靜態(tài)方法可以直接通過類名引用。

類實(shí)例是在類加載之后才進(jìn)行的。

下邊的例子針對(duì)靜態(tài)代碼塊和默認(rèn)構(gòu)造參數(shù)、PostConstruct方法進(jìn)行對(duì)比,根據(jù)輸出結(jié)果可知靜態(tài)代碼塊是先加載,然后是默認(rèn)構(gòu)造函數(shù),最后才是PostConstruct修飾的方法。所以如果想要在靜態(tài)代碼塊中使用spring注入的屬性需要做些特殊處理(后邊會(huì)講到)。

@Component
public class FuncLoadOrderService {
    //記錄每個(gè)步驟執(zhí)行的順序
    private static AtomicLong step = new AtomicLong(0);
    //默認(rèn)構(gòu)造參數(shù)
    public FuncLoadOrderService() {
        System.out.println("construct run step " + step.getAndIncrement());
    }
    //靜態(tài)代碼塊
    static {
        System.out.println("static block run step " + step.getAndIncrement());
    }
    //
    @PostConstruct
    public void constructFunc() {
        System.out.println("PostConstruct run step " + step.getAndIncrement());
    }
}

結(jié)果輸出

static block run step 0
construct run step 1
PostConstruct run step 2

@Value屬性注入

普通屬性注入

此處說的普通屬性為非static變量,類似如下聲明

//這就是一個(gè)普通屬性
private String testConfigId;
  • 結(jié)論先行。
  • 對(duì)于這種注入方式,由于實(shí)例是在默認(rèn)構(gòu)造參數(shù)執(zhí)行之后才會(huì)創(chuàng)建,且方法加載順序?yàn)?靜態(tài)代碼塊 --> 靜態(tài)方法 --> 默認(rèn)構(gòu)造參數(shù) --> PostConstruct修飾的方法。
  • 所以普通屬性使用@Value注入的變量,只有在PostConstruct修飾的方法可以取到值,即只有對(duì)象bean完成了初始化才可以獲取到配置值。
  • 想在PostConstruct前的幾步中取到值需要直接讀取配置文件,加載內(nèi)容。

屬性的普通注入方式如下,直接使用@Value注解就可以注入配置文件中的配置。

@Value("${test.configId}")
private String testConfigId;

這種方式是工作中比較常用的注入方式了,但是因?yàn)関alue是在類實(shí)例創(chuàng)建之后才注入的,

所以這里有兩個(gè)注意點(diǎn)

  • 1.默認(rèn)構(gòu)造參數(shù)中無法獲取注入的value
  • 2.static修飾的方法無法獲取注入的value

如果一定想要在默認(rèn)構(gòu)造參數(shù)里獲取@Value注入的值怎么辦呢?想一想為什么默認(rèn)構(gòu)造參數(shù)無法使用@Value注入的值~~

是不是因?yàn)榇藭r(shí)bean還沒有創(chuàng)建,類對(duì)象還沒有實(shí)例化,所以所有依賴Bean創(chuàng)建方式來注入值的方式都不可以使用,因此可以考慮直接讀取配置文件來獲取值。

這里提供兩種方式。第一種是使用 YamlMapFactoryBean 將配置文件的內(nèi)容讀到map中

YamlMapFactoryBean yaml = new YamlMapFactoryBean();
yaml.setResources(new ClassPathResource("application.yml"));
Map<String, Object> configMap = yaml.getObject();

這個(gè)方式可以達(dá)到目的,但是數(shù)據(jù)是嵌套的map,沒有按照key展開,使用起來不是很方便。

比如配置文件中內(nèi)容如下,如果用YamlMapFactoryBean方式讀配置,只能先 map.get(“test”) 獲取返回值,進(jìn)行類型轉(zhuǎn)換,再做其他處理

test:
  configId: 1oiieuu
  configMap: "{\"id\":123,\"key\":12333}"

第二種方式和第一個(gè)類似,只不過讀出來的數(shù)據(jù)是按照key做了展開。

這種方式使用的是 YamlPropertiesFactoryBean

YamlPropertiesFactoryBean yamlProperties = new YamlPropertiesFactoryBean();
yamlProperties.setResources(new ClassPathResource("application.yml"));
Properties properties = yamlProperties.getObject();

對(duì)于上邊提到的同樣的配置,如果想讀configId,可以直接使用 properties.get(“test.configId”) / properties.getProperty(“test.configId”) 等方法。

使用 YamlPropertiesFactoryBean 的方式最接近直接用@Value,強(qiáng)烈推薦??!

static塊、默認(rèn)構(gòu)造方法獲取@Value值

對(duì)于static代碼塊和默認(rèn)構(gòu)造方法,想要獲取配置文件中的值,只能通過將配置文件讀到內(nèi)存,轉(zhuǎn)成map、properties等方法(也可以轉(zhuǎn)json、yaml等),來獲取值。

靜態(tài)方法中獲取@Value值

上邊講到普通的變量使用@Value修飾,在靜態(tài)方法中獲取不到值,是因?yàn)殪o態(tài)方法中想要獲取普通變量,需要用new來創(chuàng)建對(duì)象,new出來的對(duì)象沒有注入@Value,所以想要在靜態(tài)方法中使用@Value修飾的對(duì)象,需要把對(duì)象定義為static類型,

代碼如下:

private static String configId;
@Value("${test.configId}")
public void setConfigId(String configId) {
      FuncLoadOrderService.configId = configId;
}
public static void staticFuncTest() {
      System.out.println("static func " + FuncLoadOrderService.configId);
}

原理

上邊我們先給出了在不同情況下使用@Value會(huì)出現(xiàn)的情況,并給出了解決方案,下邊我們來簡(jiǎn)單看下@Value為什么有些情況不能完成value注入。

  • 結(jié)論先行。
  • 對(duì)于@Value修飾的屬性、方法,在底層處理的時(shí)候和@Autowired處理邏輯是一樣的。
  • 處理邏輯是由AutowiredAnnotationBeanPostProcessor類的內(nèi)部類,AutowiredFieldElement 和 AutowiredMethodElement進(jìn)行具體邏輯處理。
  • 其中AutowiredFieldElement處理使用了相關(guān)注解的屬性
  • AutowiredMethodElement處理使用了相關(guān)注解的方法
  • 以屬性處理鏈路為例,給出處理邏輯的調(diào)用鏈
  • AutowiredFieldElement#inject#resolveDependency#doResolveDependency#convertIfNecessary
//AutowiredAnnotationBeanPostProcessor默認(rèn)構(gòu)造方法,把此類可以處理的類型加入到列表中,從代碼中可以看到這個(gè)類可以處理 @Value、@Autowired、@Inject三種注解
public AutowiredAnnotationBeanPostProcessor() {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}

內(nèi)部類AutowiredFieldElement的關(guān)鍵源碼如下。

從源碼中可看到處理邏輯都是針對(duì)bean來進(jìn)行處理,而static修飾的方法、屬性,是在bean中獲取不到,所以static屬性使用@Value無法注入對(duì)應(yīng)的值。

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      Field field = (Field) this.member;
      Object value;
      if (this.cached) {
            //在緩存中,直接進(jìn)行屬性處理
            value = resolvedCachedArgument(beanName, this.cachedFieldValue);
      }
      else {
            //設(shè)置屬性信息
            DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
            desc.setContainingClass(bean.getClass());
            Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
            Assert.state(beanFactory != null, "No BeanFactory available");
            TypeConverter typeConverter = beanFactory.getTypeConverter();
            try {
                  value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
            }
            catch (BeansException ex) {
                  throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
            }
            synchronized (this) {
                  if (!this.cached) {
                        //加入緩存處理
                  }
            }
      }
      if (value != null) {
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
      }
}

AutowiredMethodElement和AutowiredFieldElement一樣,都是繼承自 InjectionMetadata.InjectedElement,所以對(duì)于使用@Value的方法能夠完成注入。

下邊這段代碼中configId能夠注入,就是因?yàn)锧Value使用在方法上,在bean加載時(shí)會(huì)將configId裝配到bean中。

private static String configId;
@Value("${test.configId}")
public void setConfigId(String configId) {
      FuncLoadOrderService.configId = configId;
}
public static void staticFuncTest() {
      System.out.println("static func " + FuncLoadOrderService.configId);
}

結(jié)論

@Value是平時(shí)用的比較多的注解,使用時(shí)也會(huì)遇到某些情況注入失敗,所以進(jìn)行了一番了解并將了解的結(jié)論分享給大家。

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

相關(guān)文章

  • Java語言獲取TCP流的實(shí)現(xiàn)步驟

    Java語言獲取TCP流的實(shí)現(xiàn)步驟

    使用Wireshark分析網(wǎng)絡(luò)包時(shí),一個(gè)很常用的功能就是選中一個(gè)TCP報(bào)文,然后查看這個(gè)TCP報(bào)文的TCP流,從而可以進(jìn)一步分析建連是否慢了,斷連是否正常等情況,那么本文就TCP流的概念以及在Java中如何獲取,做一個(gè)簡(jiǎn)單的學(xué)習(xí),需要的朋友可以參考下
    2023-11-11
  • java設(shè)計(jì)模式系列之裝飾者模式

    java設(shè)計(jì)模式系列之裝飾者模式

    這篇文章主要為大家詳細(xì)介紹了java設(shè)計(jì)模式之裝飾者模式,裝飾者模式是一種結(jié)構(gòu)式模式,感興趣的朋友可以參考一下
    2016-02-02
  • 解決Spring Boot項(xiàng)目端口8080被占用的問題

    解決Spring Boot項(xiàng)目端口8080被占用的問題

    這篇文章主要介紹了解決Spring Boot項(xiàng)目端口8080被占用的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot分離打Jar包的兩種配置方式

    SpringBoot分離打Jar包的兩種配置方式

    這篇文章主要介紹了SpringBoot分離打Jar包的兩種配置方式,方式一是基于maven-jar-plugin,方式二是基于spring-boot-maven-plugin,文中結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • 詳解SpringBoot是如何整合SpringDataRedis的?

    詳解SpringBoot是如何整合SpringDataRedis的?

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著SpringBoot是如何整合SpringDataRedis展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • java實(shí)現(xiàn)cassandra高級(jí)操作之分頁(yè)實(shí)例(有項(xiàng)目具體需求)

    java實(shí)現(xiàn)cassandra高級(jí)操作之分頁(yè)實(shí)例(有項(xiàng)目具體需求)

    這篇文章主要介紹了java實(shí)現(xiàn)cassandra高級(jí)操作之分頁(yè)實(shí)例(有項(xiàng)目具體需求),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • SpringBoot中@RestControllerAdvice 全局異常處理的實(shí)現(xiàn)

    SpringBoot中@RestControllerAdvice 全局異常處理的實(shí)現(xiàn)

    本文主要介紹了SpringBoot中@RestControllerAdvice 全局異常處理的實(shí)現(xiàn),通過定義統(tǒng)一響應(yīng)格式、自定義異常類及測(cè)試驗(yàn)證,確保接口異常時(shí)返回指定格式的提示信息,提升錯(cuò)誤處理一致性
    2025-06-06
  • SpringBoot實(shí)現(xiàn)接口數(shù)據(jù)加解密的三種解決方案

    SpringBoot實(shí)現(xiàn)接口數(shù)據(jù)加解密的三種解決方案

    這篇文章主要介紹了SpringBoot實(shí)現(xiàn)接口數(shù)據(jù)加解密的三種解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • Springboot整合MybatisPlus的實(shí)現(xiàn)過程解析

    Springboot整合MybatisPlus的實(shí)現(xiàn)過程解析

    這篇文章主要介紹了Springboot整合MybatisPlus的實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Mybatis參數(shù)傳遞示例代碼

    Mybatis參數(shù)傳遞示例代碼

    這篇文章主要給大家介紹了關(guān)于Mybatis參數(shù)傳遞的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08

最新評(píng)論

宁陕县| 长垣县| 师宗县| 白朗县| 台江县| 江油市| 措勤县| 灌南县| 和政县| 蒙城县| 芦山县| 财经| 漳浦县| 长治县| 余干县| 开封县| 类乌齐县| 九江市| 济宁市| 高州市| 普兰店市| 南城县| 德安县| 胶州市| 邳州市| 南木林县| 来安县| 格尔木市| 稻城县| 霍林郭勒市| 达孜县| 襄汾县| 宁南县| 科技| 彰化县| 吴川市| 蒲江县| 临潭县| 曲沃县| 木里| 神木县|