具有JPA依赖性的Flyway Spring Boot Autowired Bean [英] Flyway Spring Boot Autowired Beans with JPA Dependency

查看:350
本文介绍了具有JPA依赖性的Flyway Spring Boot Autowired Bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Flyway 5.0.5并且我无法创建具有自动装配属性的java(SpringJdbcMigration)......它们最终 null



我能找到的最接近的是这个问题: Spring bean没有注入基于flyway java的迁移



答案提到它在Flyway 5中被修复但链接是我死了。

解决方案

我挣扎着由于我的JPA依赖性,这很长一段时间。我将略微编辑我的问题的标题以反映这一点...



@Autowired bean被实例化来自 ApplicationContext 。我们可以创建一个不同的bean ApplicationContextAware ,并使用它来手动连接我们的bean以用于迁移。



可以找到一个非常干净的方法这里。不幸的是,这会在使用JPA时抛出未捕获的异常(具体来说, ApplicationContext 为null)。幸运的是,我们可以通过使用 @DependsOn 注释来解决这个问题,并在设置了 ApplicationContext 之后强制执行flyway。



首先我们需要来自 SpringUtility / spring-beans-flyway2rel =nofollow noreferrer> avehlies / spring-beans-flyway2 以上。

  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
公共类SpringUtility实现ApplicationContextAware {

@Autowired
private static ApplicationContext applicationContext;

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

/ *
从应用程序上下文中获取类bean
* /
public static< T> T getBean(final Class clazz){
return(T)applicationContext.getBean(clazz);
}

/ *
如有必要,返回应用程序上下文
* /
public static ApplicationContext getContext(){
return的applicationContext;
}

}

然后,配置 flywayInitializer @DependsOn springUtility 。我在这里扩展了 FlywayAutoConfiguration ,希望保留自动配置功能。这似乎对我有用,除了在我的gradle.build文件中关闭flyway不再有效,所以我不得不添加 @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扩展FlywayConfiguration {
@Primary
@Bean(name =flywayInitializer)
@DependsOn(springUtility)
public FlywayMigrationInitializer flywayInitializer(Flyway flyway){
return super.flywayInitializer(flyway);
//返回新的FlywayMigrationInitializer(flyway,null);
}
}

只是为了完成示例,这里是迁移:

  package db.migration; 

import org.flywaydb.core.api.migration.spring.SpringJdbcMigration;
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;

@Component
公共类V2__account_name_ucase_firstname实现SpringJdbcMigration {

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

public void migrate(JdbcTemplate jdbcTemplate)抛出异常{

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

for(账户账户:账户){

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

}
}
}

感谢github上的avehlies,堆栈溢出的Andy Wilkinson和github上的OldIMP帮助我一路走来。


I am using Flyway 5.0.5 and I am unable to create a java (SpringJdbcMigration) with autowired properties... They end up null.

The closest thing I can find is this question: Spring beans are not injected in flyway java based migration

The answer mentions it being fixed in Flyway 5 but the links are dead.

What am I missing?

解决方案

I struggled with this for a long time due to my JPA dependency. I am going to edit the title of my question slightly to reflect this...

@Autowired beans are instantiated from the ApplicationContext. We can create a different bean that is ApplicationContextAware and use that to "manually wire" our beans for use in migrations.

A quite clean approach can be found here. Unfortunately, this throws an uncaught exception (specifically, ApplicationContext is null) when using JPA. Luckily, we can solve this by using the @DependsOn annotation and force flyway to run after the ApplicationContext has been set.

First we'll need the SpringUtility from avehlies/spring-beans-flyway2 above.

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 {

    @Autowired
    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;
    }

}

Then, configure a flywayInitializer with a @DependsOn for springUtility. I extended the FlywayAutoConfiguration here hoping to keep the autoconfiguration functionality. This mostly seems to have worked for me, except that turning off flyway in my gradle.build file no longer works, so I had to add the @Profile("!integration") to prevent it from running during my tests. Other than that the autoconfiguration seems to work for me but admittedly I've only run one migration. Hopefully someone will correct me if I am wrong.

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);
    }
}

And just to complete the example, here is a migration:

package db.migration;

import org.flywaydb.core.api.migration.spring.SpringJdbcMigration;
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;

@Component
public class V2__account_name_ucase_firstname implements SpringJdbcMigration {

    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);

        }
    }
}

Thanks to avehlies on github, Andy Wilkinson on stack overflow and OldIMP on github for helping me along the way.

这篇关于具有JPA依赖性的Flyway Spring Boot Autowired Bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆