Spring Framework @Value+ランダム文字列 で実行時エラー
はじめに
Spring Frameworkでは@Value
アノテーションで外部化したプロパティを注入できます。
本記事では、環境ごとに生成したランダム文字列を外部ストアに保存し、@Value
から読み込む実装で、特定環境での実行時のみエラーになる事象に遭遇したので紹介します。
要約
@Value("${...}")
では、プロパティの中に #{...}
が含まれるとSpEL (Spring Expression Language)として解釈され、パースエラーが起こり得ます。
今回は、ランダム生成した値にSpELに該当する文字列が含まれていたため、パースエラーが起きました。
特定環境でのみ発生したのは、環境ごとに異なる値を使用していたため、問題が起こり得る値と起こらない値が存在したためです。
エラーと原因
今回発生したのは下記のエラーです。
Caused by: org.springframework.expression.spel.SpelParseException: Expression [>>5ft] @0: EL1070E: Problem parsing left operand
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.internalException(InternalSpelExpressionParser.java:1062)
これはSpring Frameworkでプロパティを読み込む際に、SpELのパースエラーが発生した、というエラーです。
実際のアノテーションと、読み込まれたプロパティの値は下記です。
- アノテーション:
@Value("${some.property}")
- プロパティ:
4#{>>5ft}
プロパティを見ると、「4
」の後ろに #{>>5ft}
が続いています。
#{...}
はSpELの式を囲む構文であるため、Spring はここを“式”として認識しようとします。
結果として、#{>>5ft}
の中にある >>
(ビット演算子: 右シフト) をパースしようとして失敗し、下記のような例外が投げられます。
Caused by: org.springframework.expression.spel.SpelParseException: Expression [>>5ft] @0: EL1070E: Problem parsing left operand
実際は文字列を意図していましたが、SpEL式の構文要素#{}
が値に含まれていたため、式として解釈され、結果としてパースエラーが発生しました。
対応
直接的なエラーの原因は「SpELの構文エラー」でしたが、今回の事象のポイントは特定環境でのみ発生したことだと考えています。
つまり、根本的な原因は「未検証の設定値を個別の環境に設定した」ことと捉えています。
実際のところ、元々の事象は本番リリース時の起動チェック時に発生しています。
今回は設定値が実装上パースできない文字列だったため、デプロイ時にエラーになりましたが、これがパース可能でそのまま起動した場合、より予想できない状態になっていたと思われます。
そのため対応として、環境ごとに異なる設定値を使う場合、それぞれの値で問題なく動作することを事前に確認するようにしました。
終わりに
本記事ではランダムな設定値を環境ごとに設定した際、実行時エラーが発生する事象について紹介しました。
エラー自体も複数の条件が重なって起こる興味深いものだと思いましたが、それ以上に、前提となる条件が変われば必ず動作も変わりうる、ということを改めて感じました。
Discussion