SprintBootの@valueアノテーションを使用して構成値を取得することはできません

次のコンテンツは、作成者によるオリジナルであり、Nuggetsプラットフォームで最初に公開されました。原作者の同意と許可なしに、いかなる形式でも、いかなる組織もそれを複製することはできません。オリジナルになるのは簡単ではありませんが、少しでもお役に立てれば幸いです。

0.発生した問題

会社のプロジェクト開発で発生した最近の問題を記録します。@valueアノテーションは読み取り専用であり、デフォルト値を構成ファイルに読み取ることはできません。参照用にソリューションの精神的な旅を記録してください。

開発では、application.propertiesに新しいパラメーターspring.redis.usedを追加する必要があるためです。実際の使用では、次のように導入されます。

@Value("${spring.redis.used}")
复制代码

これは非常に一般的ですが、問題が発生します。
コードを記述して送信すると、ローカル構成ファイルが送信されません。社内の多くの小さなパートナーは、スタートアップ構成ファイルが変更されたことを知らないため、直接エラーが発生します。プロジェクトの開始時:

image.png誰でもこのスタートアップパラメータを更新できますが、「完璧」ではありません。それから私はBaiduを通してより良い解決策を見つけようとしたので、私は次の方法を見つけました。このように、コロンの後のデフォルト値は、スタートアップコンフィギュレーションファイルに存在しない場合に使用されます。

@Value("${spring.redis.used:false}")
复制代码

テスト後、目的を達成できます。構成パラメーターがなくても、プロジェクトを正常に開始でき、デフォルト値が取得されます。この時点で、問題は解決したようです。

しかし、テストを繰り返すと、別の新しい問題が見つかりました。

設定項目のパラメータは取得できません。設定してもデフォルト値として読み込まれます。

1.問題分析

1.1問題の原因を見つける

レイヤーごとに検索した後、私はついに春のソースコードで@Valueを解決するメソッドを見つけました:AbstractBeanFactoryのresolveEmbeddedValue

@Override
@Nullable
public String resolveEmbeddedValue(@Nullable String value) {
   if (value == null) {
      return null;
   }
   String result = value;
   for (StringValueResolver resolver : this.embeddedValueResolvers) {
      result = resolver.resolveStringValue(result);
      if (result == null) {
         return null;
      }
   }
   return result;
}
复制代码

このコードを少し分析します。解析された値を取得するために、ループプロジェクトで構成された値パーサーを介してすべての@valueアノテーションを処理します。次に、次の文が問題であることがわかりました。

結果=resolver.resolveStringValue(result);

各パーサーは結果を処理に取り、処理結果を処理後に結果に戻します。パーサーがそれを読み取らないがデフォルト値を読み取る場合、後続のすべてのパーサーはデフォルト値を解析および処理しているため、このパラメーターが構成されているかどうかに関係なく、プロジェクトは実際の値を読み取ることができません。

当时就很不解了,公司项目并没有配置过额外的解析器啊,按理就只有一个 springboot 自动的配置。所以就调试到这块,拿到真实的 embeddedValueResolvers 值看个究竟。

1.2为什么会出现多个解析器

下面放debug截图

image.png

如果是用过 ureport 报表的同学应该能看明白了,这两个解析器都是因为我们项目中引入了一个开源报表工具 Ureport,而这个开源报表里面自动配置了这两个解析器

对这个开源报表的配置就不进入分析了,总之就是这个工具引入导致的。

那这时下一个疑问就出来了,为什么这两个Ureport 解析器在前面,而 springboot 默认的解析器位于最后呢?

1.3 Resolver 的加载顺序

下面是这3个解析器的 Order属性:

第1个解析器:Order 100
第2个解析器:Order 2147483647
第3个解析器(springboot自带):Order 2147483647

下面两个order 值应该是没有配置过 order 属性而自带的,第1个order 应该是在初始化时有配置文件指定的,于是经过一阵搜索找到下面这段 Ureport 的配置代码

package com.bstek.ureport;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

public class UReportPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
    public UReportPropertyPlaceholderConfigurer() {
        this.setIgnoreUnresolvablePlaceholders(true);
        this.setOrder(100);
    }
}
复制代码

原来如此,那我们的解决方法就和它一样,把springboot 默认的解析器 order 顺序配置到 Ureport 前就好了

1.4 重新配置 spring resolver 顺序

在项目中加入一段自定义配置:

@Configuration
public class PropertySourcesPlaceholderConfigurer extends org.springframework.context.support.PropertySourcesPlaceholderConfigurer {
   PropertySourcesPlaceholderConfigurer(){
      setIgnoreUnresolvablePlaceholders(true);
      setOrder(99);
   }
}
复制代码

测试下来正常解决该问题。

2.事后思考

虽然我们的问题得到解决,但是始终觉得 spring 在解析那块的处理似乎有问题。这样如果有多个配置文件,默认解析器没有读取到配置文件,是不是也会造成后面自定义的解析器也得不到真实值?

我也怀疑是不是我们引入的 spring 版本过旧了,而新的版本是不是已经修复此问题?
于是到 spring 的github 里面去看了最新的代码依旧如此。

次に、問題に移動し、次のキーワードで検索しました。

is:issue is:open resolveEmbeddedValue

案の定、2人の仲間が私たちとほぼ同じ質問をしました。リンクは次のとおりです。興味のある友達が来て見てみることができます。

#@ Valueのプロパティプレースホルダーにデフォルト値が構成されている場合、後続のエンベディッドバリューリゾルバーは、元の値ではなくデフォルト値を解決するように求められます#26328

#現在のリゾルバーがnullを返したときに、次のリゾルバーの解決を許可する#26247

それらはすべて2020年に提案されました。州のラベル「トリアージ待ち」を読んだ後、公式の意味がわかりません。

image.png

フラグを立てて、将来それについて考えるときは、関係者が問題の提案を受け入れるかどうかを確認し、この処理コードを再変更してください。

おすすめ

転載: juejin.im/post/7084635819691999239