3

I'm migrating my existing Spring Boot 2.1.x application to 2.6.x. I want the following behavior (for integration tests which uses embedded H2 database), which is working fine in 2.1.x (obviously) but I'm struggling to achieve the same behavior in 2.6.x.

  1. Create DDL automatically (without any custom SQL script)
  2. Execute custom DML (data.sql)
  3. Initialize beans which implements InitializingBean and use data populated in step #2. Eg. Cache database table records for application to use later

Problem #1 (Solved)

2.6.x was no longer created DDL automatically by default. So adding below properties explicit seemed to be the solution.

spring.jpa.generate-ddl = true
spring.jpa.hibernate.ddl-auto = create-drop

This solves Step #1 with 2.6.x.

Problem #2 (Solved)

Starting from 2.5, Boot was running scripts in data.sql before Hibernate is initialized. Hence, data.sql was failing. To make Boot wait for DDL creation to complete, adding below property seemed to be the solution.

spring.jpa.defer-datasource-initialization = true

This solves *Step #2 with 2.6.x.

Problem #3 (Need solution)

Seemingly because of setting spring.jpa.defer-datasource-initialization to true, Step #3 is happening before Step #2 i.e. in 2.6.x. This cause beans to initialize with empty database tables e.g. Cache is populated with no entries. These are causing my tests to fail.

I played with properties like spring.jpa.defer-datasource-initialization, spring.data.jpa.repositories.bootstrap-mode and spring.sql.init.mode to workaround this without any luck.

Dilip Raj Baral
  • 3,060
  • 6
  • 34
  • 62

2 Answers2

1

You can annotate your InitializingBean (or the @Bean method producing it) with @DependsOnDatabaseInitialization. The bean will then only be created or initialized after the database initialization has completed.

Behind the scenes, the annotation will let the bean factory be configured such that your InitializingBean depends on any DataSourceScriptDatabaseInitializer, and in particular the one that executes the data.sql.

There is more information on this in the official reference documentation: https://docs.spring.io/spring-boot/docs/2.7.15/reference/html/howto.html#howto.data-initialization.dependencies.depends-on-initialization-detection

Henning
  • 3,055
  • 6
  • 30
0

You can defer executing those InitializingBean's logic to just after the spring context finish startup by using ApplicationRunner or CommandLineRunner . At that moment , all beans initialisation , bootstrapping hibernate and executing data.sql should already be done.

Something likes:

@Service
public class FooService implements ApplicationRunner {


    @Override
    public void run(ApplicationArguments args) throws Exception {
        //cache database table records for later use...
    }
}

The end result is the same as using InitializingBean approach (i.e. After the application startup, the DB records will be cached in that bean)

Ken Chan
  • 84,777
  • 26
  • 143
  • 172