Spring Boot Flyway Sping Boot Autowired Bean(依赖JPA)

klsxnrf1  于 12个月前  发布在  Spring
关注(0)|答案(5)|浏览(147)

我使用的是Flyway 5.0.5,我无法创建一个带有自动连接属性的java(SpringJdbcMigration).它们最终变成了null
我能找到的最接近的是这个问题:Spring beans are not injected in flyway java based migration
答案提到它在Flyway 5中被修复,但链接已经死了。
我错过了什么?

pb3s4cty

pb3s4cty1#

由于我对JPA的依赖,我为此挣扎了很长时间。我将稍微编辑一下我的问题的标题,以反映这一点。
@Autowired bean是从ApplicationContext示例化的。我们可以创建一个不同的bean,即ApplicationContextAware,并使用它来“手动连接”我们的bean以用于迁移。
here是一个非常简洁的方法。不幸的是,在使用JPA时,这会抛出一个未捕获的异常(具体来说,ApplicationContext为null)。幸运的是,我们可以通过使用@DependsOn注解来解决这个问题,并在设置ApplicationContext后强制运行flyway。
首先,我们需要上面的avehlies/spring-beans-flyway2中的SpringUtility

package com.mypackage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtility implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /*
        Get a class bean from the application context
     */
    public static <T> T getBean(final Class clazz) {
        return (T) applicationContext.getBean(clazz);
    }

    /*
        Return the application context if necessary for anything else
     */
    public static ApplicationContext getContext() {
        return applicationContext;
    }

}

字符串
然后,为springUtility配置一个flywayInitializer和一个@DependsOn。我在这里扩展了FlywayAutoConfiguration,希望保留自动配置功能。这似乎对我很有效,除了在我的www.example.com文件中关闭flywaygradle.build不再起作用,所以我不得不添加@Profile("!integration"),以防止它在我的测试期间运行。除此之外,自动配置似乎对我有用,但无可否认,我只运行了一次迁移。希望有人如果我错了,他会纠正我的。

package com.mypackage;

import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayConfiguration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.DependsOn;

import com.mypackage.SpringUtility;

@Configuration
@Profile("!integration")
class MyFlywayConfiguration extends FlywayConfiguration {
    @Primary
    @Bean(name = "flywayInitializer")
    @DependsOn("springUtility")
    public FlywayMigrationInitializer flywayInitializer(Flyway flyway){
        return super.flywayInitializer(flyway);
        //return new FlywayMigrationInitializer(flyway, null);
    }
}


为了完成这个例子,这里是一个迁移:

package db.migration;

import org.flywaydb.core.api.migration.spring.BaseSpringJdbcMigration;
import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.stereotype.Component;

import com.mypackage.repository.AccountRepository;
import com.mypackage.domain.Account;

import com.mypackage.SpringUtility;

import java.util.List;

public class V2__account_name_ucase_firstname extends BaseSpringJdbcMigration {

    private AccountRepository accountRepository = SpringUtility.getBean(AccountRepository.class);

    public void migrate(JdbcTemplate jdbcTemplate) throws Exception {

        List<Account> accounts = accountRepository.findAll();

        for (Account account : accounts) {

            String firstName = account.getFirstName();
            account.setFirstName(firstName.substring(0, 1).toUpperCase() + firstName.substring(1));
            account = accountRepository.save(account);

        }
    }
}


感谢github上的avehlies,堆栈溢出的Andy威尔金森和github上的OldIMP,他们沿着帮助了我。
如果你使用的是Flyway的更新版本,那么扩展BaseJavaMigration而不是BaseSpringJdbcMigration,因为后者已经过时了。另外,看看下面用户Wim Deblauwe的两条评论。

z4iuyo4d

z4iuyo4d2#

该功能还没有进入Flyway。它正在被this issue跟踪。在撰写本文时,该问题尚未解决,并被分配到5.1.0里程碑。

kb5ga3dv

kb5ga3dv3#

看来@mararn1618提供的更新答案在官方文档中记录,所以我将在这里提供一个工作设置。感谢@mararn1618在这个方向上的指导。
免责声明,它是用Kotlin写的:)
首先,您需要一个用于加载迁移类的配置,在Sping Boot (可能还有Spring)中,您需要FlywayConfigurationCustomizer的实现或FlywayAutoConfiguration.FlywayConfiguration的设置。

配置a,已测试

import org.flywaydb.core.api.configuration.FluentConfiguration
import org.flywaydb.core.api.migration.JavaMigration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.flyway.FlywayConfigurationCustomizer
import org.springframework.context.ApplicationContext
import org.springframework.stereotype.Component

@Component
class MyFlywayConfiguration @Autowired constructor(
        val applicationContext: ApplicationContext
) : FlywayConfigurationCustomizer {
    override fun customize(configuration: FluentConfiguration?) {
        val migrationBeans = applicationContext.getBeansOfType(JavaMigration::class.java)
        val migrationBeansAsArray = migrationBeans.values.toTypedArray()
        configuration?.javaMigrations(*migrationBeansAsArray)
    }
}

字符串

配置选项B,未经测试,但也应该工作

import org.flywaydb.core.api.migration.JavaMigration
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
import org.springframework.boot.autoconfigure.flyway.FlywayConfigurationCustomizer
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class MyFlywayConfiguration : FlywayAutoConfiguration.FlywayConfiguration() {
    @Bean
    fun flywayConfigurationCustomizer(applicationContext: ApplicationContext): FlywayConfigurationCustomizer {
        return FlywayConfigurationCustomizer { flyway ->
            val p = applicationContext.getBeansOfType(JavaMigration::class.java)
            val v = p.values.toTypedArray()

            flyway.javaMigrations(*v)
        }
    }
}


有了它,你可以像其他Spring bean一样编写迁移:

import org.flywaydb.core.api.migration.BaseJavaMigration
import org.flywaydb.core.api.migration.Context
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

@Component
class V7_1__MyMigration @Autowired constructor(
) : BaseJavaMigration() {
    override fun migrate(context: Context?) {
        TODO("go crazy, mate, now you can import beans, but be aware of circular dependencies")
    }
}


旁注:

  • 小心循环依赖,您的迁移很可能不依赖于存储库(这也是有意义的,毕竟您正在准备它们)
  • 确保您的迁移位于Spring扫描类的位置。
  • 我还没有测试过,但很可能应该谨慎混合这些迁移的路径和Flyway扫描迁移的位置
0g0grzrc

0g0grzrc4#

如果你正在使用deltaspike,你可以使用BeanProvider来获取对你的DAO的引用。
更改您的DAO代码:

public static UserDao getInstance() {
    return BeanProvider.getContextualReference(UserDao.class, false, new DaoLiteral());
}

字符串
然后在您的迁移方法中:

UserDao userdao = UserDao.getInstance();


这就是你的推荐人
(来源:Flyway Migration with Java)

xqk2d5yq

xqk2d5yq5#

当前的flyway 6.5.5版本已经发布,并且从6.0.0版本返回,我相信已经提供了对spring beans的支持。(使用@autowired),但直觉是您的Migration类也应该由Spring管理以解决依赖关系。有一个很酷且简单的方法,通过覆盖Flyway的默认行为,查看https://reflectoring.io/database-migration-spring-boot-flyway/这篇文章用代码片段清楚地回答了你的问题。

相关问题