LoginSignup
0
0

More than 5 years have passed since last update.

Flyway の DDL を main/resources/migration に配置すると AnnotationConfigApplicationContext のインスタンス化に時間を要する

Last updated at Posted at 2017-09-15

概要

下記のような構成にて JUnit にてテストを実施した際に、表題の現象が発生いたしました。

src
  |- main 
  |     |- resources
  |     |      |- db.migration/V1__createSchema.sql (flyway のマイグレーションDDL)
  |     |- application-development.properties
  |- test 
  |     |- resources
  |           |- application-unit.properties
application-unit.properties
flyway.schemas=PUBLIC
flyway.locations=filesystem:src/main/resources/db/migration/
EnvironmentHelper.java
// DI コンテナにて管理していないクラスからも application.properties にて定義された値を取得できるようにする
public final class EnvironmentHelper {

    private static Environment environment;
    static {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        environment = context.getEnvironment();
    }
}

補足
下記の構成のように test 配下に flyway のリソースを配置すると早かった、、、気がします。。。

src
  |- main 
  |     |- resources
  |     |- application-development.properties
  |- test 
  |     |- resources
  |     |      |- db.migration/V1__createSchema.sql
  |            |- application-unit.properties

また、main, test 配下に flyway の DDL を配置すると、flyway のファイルが 2 つ存在するために起動時エラーが発生する動作となりました。

原因についての推測

下記のようなログが複数回出力されていることから、ApplicationContext を初期化する際、ディレクトリ内の class ファイルをサーチしているものと考えられます。

DEBUG-2017-09-15 15:45:03,474---org.springframework.core.io.support.PathMatchingResourcePatternResolver-775-main-Searching directory [/Users/hoge/root/out/test/classes/example] for files matching pattern [/Users/hoge/root/out/test/classes/example/**/*.class]
DEBUG-2017-09-15 15:45:03,505---org.springframework.core.io.support.PathMatchingResourcePatternResolver-775-main-Searching directory [/Users/hoge/root/out/test/classes/example/helper] for files matching pattern [/Users/hoge/root/out/test/classes/example/**/*.class]
DEBUG-2017-09-15 15:45:03,537---org.springframework.core.io.support.PathMatchingResourcePatternResolver-775-main-Searching directory [/Users/hoge/root/out/test/classes/example/service] for files matching pattern [/Users/hoge/root/out/test/classes/example/**/*.class]

… many similar logs ….

上記ログが複数回出力されます。

回避策

こちら の記事を拝見させていただき、ApplicationListener を使用して、Environment オブジェクトを取得して、静的にアクセスできるようにしました。
また、アプリケーションの起動にてハンドリングされるイベントを調査したところ、下記の順にてログが出力されたことから、ApplicationReadyEvent クラスにて上記処理を実施いたしました。

output.log
INFO -example.spring.ApplicationEventHandler-17-main-org.springframework.boot.autoconfigure.jdbc.DataSourceInitializedEvent
INFO -example.spring.ApplicationEventHandler-17-main-org.springframework.context.event.ContextRefreshedEvent
INFO -example.spring.ApplicationEventHandler-17-main-org.springframework.boot.context.event.ApplicationReadyEvent
INFO -example.spring.ApplicationEventHandler-17-main-org.springframework.boot.autoconfigure.jdbc.DataSourceInitializedEvent
INFO -example.spring.ApplicationEventHandler-17-main-org.springframework.context.event.ContextRefreshedEvent
ApplicationEventHandler.java
@Component
@Slf4j
public class ApplicationEventHandler implements ApplicationListener<ApplicationReadyEvent> {

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.info("application is ready to start...");
        Environment environment = event.getApplicationContext().getEnvironment();
        EnvironmentHelper.setEnvironment(environment);
    }
}

参考情報

タイトル : Interface ApplicationListener
アドレス : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationListener.html

タイトル : Class ApplicationReadyEvent
アドレス : https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/event/ApplicationReadyEvent.html

補足

上記の方針を採用したおかげで、環境ごとに用意していた @Profile を定義したクラスは不要かと思いましたが、テスト用の Bean を Injectionするために以前として下記のようなクラスが必要でした。

TestEnvironment.java
@TestConfiguration
@Profile("test")
@PropertySource("classpath:application-test.properties")
public class TestEnvironment {
}

おそらく下記のように、テストクラスの基底クラスにて Bean を取得しているためであると思います。

AbstractBaseTest.java
@SpringBootTest(classes = Application.class)
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
public abstract class AbstractBaseTest {
    @Rule
    //public にしないと怒られる
    public TestResource testResource;

    public void setUp() {
        ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
        testResource = context.getBean(TestResource.class);
    }
}

@Autowired でなぜかテストクラスにテスト用のモジュールをバインドできなかったために下記のように実装しております。。TestResource を Bean に登録するクラス内にて Environment を Autowired しておりますが、@Profile クラスが存在しない場合、アプリケーション開始時に期待するキー項目を Environment から取得できませんでした。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0