【问题标题】:Spring Boot 2.1.0 with Flyway 4.2.0Spring Boot 2.1.0 和 Flyway 4.2.0
【发布时间】:2019-04-19 23:24:48
【问题描述】:

我想将我的新项目升级到 Spring Boot 版本 2.1.0,但我受限于 Oracle 11 数据库,Flyway 4.2.0 库支持该数据库。一切都在 Spring Boot 2.0.5 版本上正常运行,但是当移动到 2.1.0 版本时,我收到此错误:

java.lang.NoClassDefFoundError: 
org/flywaydb/core/api/configuration/FluentConfiguration

POM配置如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <ojdbc6.version>11.2.0.1</ojdbc6.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.oracle.jdbc</groupId>
        <artifactId>ojdbc6</artifactId>
        <version>${ojdbc6.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.flywaydb</groupId>
        <artifactId>flyway-core</artifactId>
        <version>4.2.0</version>
    </dependency>
</dependencies>

更新

我可以通过@Configuration 解决问题(或者当然添加到主类),但问题是它的错误还是功能?在 2.1.0 版本之前,一切都是通过自动配置完成的,并且开箱即用。

@Bean(initMethod = "migrate")
Flyway flyway() {
    Flyway flyway = new Flyway();
    flyway.setBaselineOnMigrate(true);
    flyway.setDataSource("jdbc:oracle:thin:@localhost:1521:xe", "USER", "PASSWORD1");
    return flyway;
}

【问题讨论】:

  • 这根本不是错误。 Spring Boot 依赖于 Flyway 5.2.1,它的 API 与您使用的旧版本不同。
  • 是的,我注意到了,但不能以某种方式将它排除在 pom.xml 中以支持旧版本吗?我可以找到正确的依赖项,但它正在寻找这个 FluentConfiguration 类。
  • 当然可以。但这不会改变配置 Flyway 的 Spring Boot 代码,它使用仅存在于最新版本 Flyway 中的新类。打个比方,如果你用 Java 8 编译使用 java.util.stream 的类,然后尝试在 Java 7 上运行该代码,那是行不通的,因为 Java 7 中不存在 java.util.stream .
  • 您是如何测试您的应用的?

标签: java spring-boot flyway


【解决方案1】:

我在 PostgreSQL 9.2 也遇到了同样的问题,使用下面的类解决了这个问题。

请注意,您可能在 Spring Boot 属性中设置的所有自定义属性都将被忽略,因为这会用您自己的方式替换整个 Flyway 自动配置。因此,您可能需要添加一些额外的代码以满足您的需求。

@Configuration
class FlywayConfig {
    @Bean
    fun flyway(dataSource: DataSource): Flyway {
        val flyway = Flyway()
        flyway.dataSource = dataSource
        return flyway
    }

    @Bean
    fun flywayInitializer(flyway: Flyway): FlywayMigrationInitializer {
        return FlywayMigrationInitializer(flyway, null)
    }

    /**
     * Additional configuration to ensure that [EntityManagerFactory] beans depend on the
     * `flywayInitializer` bean.
     */
    @Configuration
    class FlywayInitializerJpaDependencyConfiguration : EntityManagerFactoryDependsOnPostProcessor("flywayInitializer")
}

PS:这是 Kotlin 代码,但您应该能够相当轻松地将其转换为 Java。

【讨论】:

  • 嗨。是的,这正是我试图做的,请看我的评论;以编程方式进行配置。问题是,这是正确的方法吗?为什么以这种方式更改自动配置?如果我不能使用 application.properties,我如何为不同的环境配置不同的数据源?谢谢
  • 你可以使用application.properties。只是不要期望 flyway 属性会产生任何影响,因为 Spring Boot 不会再读取和应用它们了。其他与 Flyway 无关的,仍然可以使用。
  • 如何让它在 Spring Boot 测试中工作?我需要为 flyway 加载不同的属性以进行测试,但是 Flyway bean 不可用,或者当 Ier 手动创建 Flyway bean 时,其他 bean 会丢失。谢谢
  • @JBNizet 作为一个不了解 Kotlin 的人,除了最后一行,一切都可以理解。
  • @Younes_EO 最后一行:`@Configuration public static class FlywayInitializerJpaDependencyConfiguration extends EntityManagerFactoryDe​​pendsOnPostProcessor { public FlywayInitializerJpaDependencyConfiguration() { super("flywayInitializer"); } }`
【解决方案2】:

我为 Spring Boot 2.1.1 进行了配置,还必须重新定义 bean FlywayDefaultDdlModeProvider。

@Configuration
@ConditionalOnProperty(prefix = "spring.flyway", name = "enabled", matchIfMissing = true)
public class LegacyFlywayAutoConfiguration {

    @Bean
    @Primary
    public SchemaManagementProvider flywayDefaultDdlModeProvider(ObjectProvider<Flyway> flyways) {
        return new SchemaManagementProvider() {
            @Override
            public SchemaManagement getSchemaManagement(DataSource dataSource) {
                return SchemaManagement.MANAGED;
            }
        };
    }

    @Bean(initMethod = "migrate")
    public Flyway flyway(DataSource dataSource) {
        Flyway flyway = new Flyway();
        flyway.setBaselineOnMigrate(true);
        flyway.setDataSource(dataSource);
        return flyway;
    }

    @Bean
    public FlywayMigrationInitializer flywayInitializer(Flyway flyway) {
        return new FlywayMigrationInitializer(flyway, null);
    }

    /**
     * Additional configuration to ensure that {@link JdbcOperations} beans depend
     * on the {@code flywayInitializer} bean.
     */
    @Configuration
    @ConditionalOnClass(JdbcOperations.class)
    @ConditionalOnBean(JdbcOperations.class)
    protected static class FlywayInitializerJdbcOperationsDependencyConfiguration
            extends JdbcOperationsDependsOnPostProcessor {

        public FlywayInitializerJdbcOperationsDependencyConfiguration() {
            super("flywayInitializer");
        }

    }
}

【讨论】:

  • 你可以在@SpringBootTest 中使用它吗?
  • 是的,被覆盖的配置本身适用于@SpringBootTest。但通常你不知道t want to use Oracle database for integration test, so I dont 仅将其用于测试。我正在为@SpringBootTest 使用 H2 数据库,最新的 Flyway 版本没有任何问题。虽然,为了兼容性,我没有为集成测试创建自己的 Flyway 配置。
  • 是的,这就是我想做的,但不知何故我想不出正确的方法。如果我在测试/资源中包含 application.yml,则 Flyway Bean 被实例化,并为版本 5+ 实例化。如果我将@Configuration 或@TestCONfiguration 放在某处,那么我可以通过编程方式创建它,但是其他Bean(Daos、Services)为空,因为我也需要手动创建它们。我只想手动创建 Flyway Bean,一切都留在 Spring 上。
  • 必须将 spring.main.allow-bean-definition-overriding=true 添加到 application.properties 但它有效!
【解决方案3】:

使用 Javassist 库,您可以检测 FlywayDB 库以记录不再支持 Oracle 版本,而不是引发致命异常(通过将 ensureDatabaseIsCompatibleWithFlywayEdition 方法调用包装在 try-catch 子句中)。就我而言,FlywayDB 社区版 (5.2.4) 似乎可以在我完成后与 Oracle 11.2 一起正常工作。这个解决方案有它的缺点,但在我的情况下它是最好的选择(数据库应该很快升级)所以也许有人会发现它也很有用。理想情况下,下面的代码应该先在您的应用程序中运行。 请自行承担使用风险。

public static void suppressIncompatibleDatabaseVersionCheck() {
    try {
        CtClass ctClass = ClassPool.getDefault().get("org.flywaydb.core.internal.database.base.Database");
        ctClass.defrost();
        CtMethod method = ctClass.getDeclaredMethod("ensureDatabaseIsCompatibleWithFlywayEdition");
        CtClass etype = ClassPool.getDefault().get("java.lang.Exception");
        method.addCatch("{ LOG.warn(\"Exception suppressed: \" + $e); return ;}", etype);
        ctClass.toClass();
    } catch (NotFoundException | CannotCompileException e) {
        log.error("Could not instrument FlywayDB code.", e);
    }
}

【讨论】:

    【解决方案4】:

    使用下面的依赖,会被this解析。

    <dependency>
        <groupId>org.flywaydb</groupId>
        <artifactId>flyway-core</artifactId>
        <version>5.2.3</version>
    </dependency>
    

    【讨论】:

    • 正如我在问题中提到的,由于不支持 Oracle 11,我不能使用高于 4.2.0 的 flyway 版本
    • 对我来说同样不能使用更高版本的flyway,除非你说flyway-core 5与ojdbc6 11和oracle 11兼容(不是)
    猜你喜欢
    • 2019-05-10
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    • 2019-03-18
    • 2019-04-25
    • 2017-10-11
    相关资源
    最近更新 更多