💨

Java / Spring Bootの環境変数でハマった話

2024/03/18に公開

Spring Bootの環境変数でハマった話です。

「あれ、Spring Bootのアプリケーションが昔つかってたDBをdatasourceにしようとしてる。」
「はいはい、設定ファイルに指定いれるだけやろ」と指定しても、前の接続先を見ている。なんなら稼働してないDBだし、

「なんで????????」となったので、Spring Bootを用いた開発で使用する環境変数周りを備忘録としてまとめておきます。

Spring Boot ✗ IntelliJを使用している時よくつかう環境変数

Spring Bootのアプリケーションでよく使う環境変数の1つ目

application.propertiesapplication-local.propertiesなどで指定するあれです。

DBの接続先などアプリケーションで使用する情報をpropertiesファイルに環境変数として定義します。

spring.datasource.url=jdbc:postgresql://localhost:5432/my-db
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driverClassName=org.postgresql.Driver

ただし、application.propertiesは本番、テスト、ローカルすべての環境で反映されます。

本番環境の設定値がGitで管理対象になるのはセキュリティ的によろしくないため、
application-prod.propertiesなどを以下のように指定し、

spring.datasource.url=${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USER}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}

環境変数をpropertiesファイルに定義し、デプロイ先で環境変数を読み込む形にすることが多いように思います。

本番環境での起動時にはprofileをprodに指定して、起動する形です。

propertiesファイルのprofileは任意のものを使用することができます。
application-{プロファイル名}.propertiesのように指定すし、起動時にプロファイルを明示すればよいです。

Spring Bootのアプリケーションでよく使う環境変数の2つ目

例えば、ローカルであるプロファイルを指定して、テストの実行をしたいとしましょう。

そんなときはIntelliJで環境変数を指定することで対応できます。

Run/Debug Configurationsというメニューがあり、その中のEnvironmental Variableで画像のように環境変数を定義することができます。

intelliJ-environment-var

ちなみに2個以上の環境変数が必要な場合は;区切りで記載すればよいです。

ローカルでの開発時でSpring Bootで使用する環境変数は大きくはこの2つを理解しておけばOKです。

ハマったこと

では、この環境変数周りでハマった理由......それは1年前の自分がMacの環境変数に
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USER_NAME,SPRING_DATASOURCE_USER_PASSWORDを定義していたからでした。

ここにたどり着くまでに、なかなか時間がかかったのですが、これがわかれば簡単ということで
.zshrcに`定義されていた3つの環境変数を削除しました。

よし、いよいよテストがまともに動くようになるな!と意気揚々とTestを実行したところ、

java.lang.IllegalStateException: 
Failed to load ApplicationContext for [WebMergedContextConfiguration@6c8efde4 testClass = template.TemplateApplicationTests, locations = [], classes = [template.TemplateApplication], 
contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], 
propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], 
contextCustomizers = [org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, 
org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@6187d1f5, 
org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@46944ca9, 
org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@5674e1f2,
org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, 
org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@6986bbaf, 
org.springframework.boot.test.context.SpringBootTestAnnotation@422225f3], 
resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, 
parent = null]
Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'dataSource' defined in class path resource 
[org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: 
Failed to instantiate [com.zaxxer.hikari.HikariDataSource]:
Factory method 'dataSource' threw exception with message: 
Failed to load driver class com.mysql.cj.jdbc.Driver in either of HikariConfig class loader or Thread context classloader

使ってるPostgreSQLなんです。MySQL使ってないねんけどな。。。。。。という気持ちになりましたが、 他に環境変数を読み込んでいるところがないかを探しました。

すると、まだ残っていた環境変数を発見しました。
intelliJ-environment-var2

IntelliJが読み込んでいるシステムの環境変数でした。

「こいつがまだ残っていたか」ということできれいに消しさったところ意図した通り動作するようになりました。

まとめ

アプリケーション固有の環境変数をローカルの環境変数に定義するなんてだめ!と当時独学中の自分に言いたくなりました。
(Spring難しい)

Discussion