Add options for Flyway to have its own DataSource

Either set flyway.[url,user,password] or create a DataSource
@Bean and mark it @FlywayDataSource.

Fixes gh-807
pull/951/merge
Dave Syer 11 years ago
parent 9f52a0dbd7
commit 32295b9bdc

@ -61,9 +61,13 @@ public class FlywayAutoConfiguration {
@Autowired @Autowired
private ResourceLoader resourceLoader = new DefaultResourceLoader(); private ResourceLoader resourceLoader = new DefaultResourceLoader();
@Autowired @Autowired(required = false)
private DataSource dataSource; private DataSource dataSource;
@Autowired(required = false)
@FlywayDataSource
private DataSource flywayDataSource;
@PostConstruct @PostConstruct
public void checkLocationExists() { public void checkLocationExists() {
if (this.properties.isCheckLocation()) { if (this.properties.isCheckLocation()) {
@ -83,9 +87,19 @@ public class FlywayAutoConfiguration {
@Bean(initMethod = "migrate") @Bean(initMethod = "migrate")
@ConfigurationProperties(prefix = "flyway") @ConfigurationProperties(prefix = "flyway")
public Flyway flyway(DataSource dataSource) { public Flyway flyway() {
Flyway flyway = new Flyway(); Flyway flyway = new Flyway();
flyway.setDataSource(dataSource); if (this.properties.isCreateDataSource()) {
flyway.setDataSource(this.properties.getUrl(), this.properties.getUser(),
this.properties.getPassword(), this.properties.getInitSqls()
.toArray(new String[0]));
}
else if (this.flywayDataSource != null) {
flyway.setDataSource(this.flywayDataSource);
}
else {
flyway.setDataSource(this.dataSource);
}
return flyway; return flyway;
} }

@ -0,0 +1,40 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.flyway;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Qualifier annotation for a DataSource to be injected in to Flyway. If used for a second
* data source, the other (main) one would normally be marked as <code>@Primary</code>.
*
* @author Dave Syer
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,
ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface FlywayDataSource {
}

@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.flyway; package org.springframework.boot.autoconfigure.flyway;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.flywaydb.core.Flyway; import org.flywaydb.core.Flyway;
@ -41,6 +42,14 @@ public class FlywayProperties {
private boolean enabled = true; private boolean enabled = true;
private String user;
private String password;
private String url;
private List<String> initSqls = Collections.emptyList();
public void setLocations(List<String> locations) { public void setLocations(List<String> locations) {
this.locations = locations; this.locations = locations;
} }
@ -64,4 +73,40 @@ public class FlywayProperties {
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
this.enabled = enabled; this.enabled = enabled;
} }
public String getUser() {
return this.user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return this.password == null ? "" : this.password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public List<String> getInitSqls() {
return this.initSqls;
}
public void setInitSqls(List<String> initSqls) {
this.initSqls = initSqls;
}
public boolean isCreateDataSource() {
return this.url != null && this.user != null;
}
} }

@ -50,6 +50,8 @@ public class DataSourceBuilder {
private ClassLoader classLoader; private ClassLoader classLoader;
private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider();
private Map<String, String> properties = new HashMap<String, String>(); private Map<String, String> properties = new HashMap<String, String>();
public static DataSourceBuilder create() { public static DataSourceBuilder create() {
@ -67,10 +69,19 @@ public class DataSourceBuilder {
public DataSource build() { public DataSource build() {
Class<? extends DataSource> type = getType(); Class<? extends DataSource> type = getType();
DataSource result = BeanUtils.instantiate(type); DataSource result = BeanUtils.instantiate(type);
maybeGetDriverClassName();
bind(result); bind(result);
return result; return result;
} }
private void maybeGetDriverClassName() {
if (!this.properties.containsKey("driverClassName")) {
String cls = this.driverClassNameProvider.getDriverClassName(this.properties
.get("url"));
this.properties.put("driverClassName", cls);
}
}
private void bind(DataSource result) { private void bind(DataSource result) {
new RelaxedDataBinder(result).bind(getPropertyValues()); new RelaxedDataBinder(result).bind(getPropertyValues());
} }

@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.flyway;
import java.util.Arrays; import java.util.Arrays;
import javax.sql.DataSource;
import org.flywaydb.core.Flyway; import org.flywaydb.core.Flyway;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -26,12 +28,16 @@ import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/** /**
* Tests for {@link LiquibaseAutoConfiguration}. * Tests for {@link LiquibaseAutoConfiguration}.
@ -66,6 +72,29 @@ public class FlywayAutoConfigurationTests {
assertEquals(0, this.context.getBeanNamesForType(Flyway.class).length); assertEquals(0, this.context.getBeanNamesForType(Flyway.class).length);
} }
@Test
public void testCreateDataSource() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"flyway.url:jdbc:hsqldb:mem:flywaytest", "flyway.user:sa");
this.context
.register(EmbeddedDataSourceConfiguration.class,
FlywayAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
Flyway flyway = this.context.getBean(Flyway.class);
assertNotNull(flyway.getDataSource());
}
@Test
public void testFlywayDataSource() throws Exception {
this.context.register(FlywayDataSourceConfiguration.class,
EmbeddedDataSourceConfiguration.class, FlywayAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
Flyway flyway = this.context.getBean(Flyway.class);
assertNotNull(flyway.getDataSource());
}
@Test @Test
public void testDefaultFlyway() throws Exception { public void testDefaultFlyway() throws Exception {
this.context this.context
@ -113,4 +142,16 @@ public class FlywayAutoConfigurationTests {
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
} }
@Configuration
protected static class FlywayDataSourceConfiguration {
@FlywayDataSource
@Bean
public DataSource flywayDataSource() {
return DataSourceBuilder.create().url("jdbc:hsqldb:mem:flywaytest")
.username("sa").build();
}
}
} }

@ -203,6 +203,9 @@ content into your application; rather pick only the properties that you need.
flyway.prefix=V flyway.prefix=V
flyway.suffix=.sql flyway.suffix=.sql
flyway.enabled=true flyway.enabled=true
flyway.url= # JDBC url if you want Flyway to create its own DataSource
flyway.user= # JDBC username if you want Flyway to create its own DataSource
flyway.password= # JDBC password if you want Flyway to create its own DataSource
# LIQUIBASE ({sc-spring-boot-autoconfigure}/liquibase/LiquibaseProperties.{sc-ext}[LiquibaseProperties]) # LIQUIBASE ({sc-spring-boot-autoconfigure}/liquibase/LiquibaseProperties.{sc-ext}[LiquibaseProperties])
liquibase.change-log=classpath:/db/changelog/db.changelog-master.yaml liquibase.change-log=classpath:/db/changelog/db.changelog-master.yaml

@ -974,13 +974,13 @@ JDBC or JPA (then that one will be picked up by any `@Autowired` injections).
@Primary @Primary
@ConfigurationProperties(prefix="datasource.primary") @ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() { public DataSource primaryDataSource() {
return new FancyDataSource(); return DataSourceBuilder.create().build();
} }
@Bean @Bean
@ConfigurationProperties(prefix="datasource.secondary") @ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() { public DataSource secondaryDataSource() {
return new FancyDataSource(); return DataSourceBuilder.create().build();
} }
---- ----
@ -1207,6 +1207,13 @@ addition Spring Boot provides a small set of properties in
{sc-spring-boot-autoconfigure}/flyway/FlywayProperties.{sc-ext}[`FlywayProperties`] {sc-spring-boot-autoconfigure}/flyway/FlywayProperties.{sc-ext}[`FlywayProperties`]
that can be used to disable the migrations, or switch off the location checking. that can be used to disable the migrations, or switch off the location checking.
By default Flyway will autowire the (`@Primary`) `DataSource` in your context and
use that for migrations. If you like to use a different `DataSource` you can create
one and mark its `@Bean` as `@FlywayDataSource` - if you do that remember to create
another one and mark it as `@Primary` if you want 2 data sources.
Or you can use Flyway's native `DataSource` by setting `flyway.[url,user,password]`
in external properties.
There is a {github-code}/spring-boot-samples/spring-boot-sample-flyway[Flyway sample] so There is a {github-code}/spring-boot-samples/spring-boot-sample-flyway[Flyway sample] so
you can see how to set things up. you can see how to set things up.

Loading…
Cancel
Save