Spring 使用 Flyway 4.2.0 启动 2.1.0
Spring Boot 2.1.0 with Flyway 4.2.0
我想将我的新项目升级到 Spring 引导版本 2.1.0,但我受限于 Oracle 11 数据库,Flyway 4.2.0[ 支持该数据库=24=]图书馆。一切在 Spring 启动版本 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 解决问题(当然也可以添加到主class),但问题是它是错误还是功能?在版本 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;
}
我用PostgreSQL 9.2遇到了同样的问题,用下面的class解决了这个问题。
请注意,您可能在 Spring 引导属性中设置的所有自定义属性都将被忽略,因为这会替换您自己的整个 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。
我为 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");
}
}
}
使用 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);
}
}
使用下面的依赖,就这样解决了
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.3</version>
</dependency>
我想将我的新项目升级到 Spring 引导版本 2.1.0,但我受限于 Oracle 11 数据库,Flyway 4.2.0[ 支持该数据库=24=]图书馆。一切在 Spring 启动版本 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 解决问题(当然也可以添加到主class),但问题是它是错误还是功能?在版本 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;
}
我用PostgreSQL 9.2遇到了同样的问题,用下面的class解决了这个问题。
请注意,您可能在 Spring 引导属性中设置的所有自定义属性都将被忽略,因为这会替换您自己的整个 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。
我为 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");
}
}
}
使用 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);
}
}
使用下面的依赖,就这样解决了
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.3</version>
</dependency>