具有JPA依赖性的Flyway Spring Boot Autowired Bean [英] Flyway Spring Boot Autowired Beans with JPA Dependency
问题描述
我正在使用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屋!