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
private ResourceLoader resourceLoader = new DefaultResourceLoader();
@Autowired
@Autowired(required = false)
private DataSource dataSource;
@Autowired(required = false)
@FlywayDataSource
private DataSource flywayDataSource;
@PostConstruct
public void checkLocationExists() {
if (this.properties.isCheckLocation()) {
@ -83,9 +87,19 @@ public class FlywayAutoConfiguration {
@Bean(initMethod = "migrate")
@ConfigurationProperties(prefix = "flyway")
public Flyway flyway(DataSource dataSource) {
public Flyway 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;
}

@ -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;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.flywaydb.core.Flyway;
@ -41,6 +42,14 @@ public class FlywayProperties {
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) {
this.locations = locations;
}
@ -64,4 +73,40 @@ public class FlywayProperties {
public void setEnabled(boolean 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 DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider();
private Map<String, String> properties = new HashMap<String, String>();
public static DataSourceBuilder create() {
@ -67,10 +69,19 @@ public class DataSourceBuilder {
public DataSource build() {
Class<? extends DataSource> type = getType();
DataSource result = BeanUtils.instantiate(type);
maybeGetDriverClassName();
bind(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) {
new RelaxedDataBinder(result).bind(getPropertyValues());
}

@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.flyway;
import java.util.Arrays;
import javax.sql.DataSource;
import org.flywaydb.core.Flyway;
import org.junit.After;
import org.junit.Before;
@ -26,12 +28,16 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException;
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.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils;
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.assertNotNull;
/**
* Tests for {@link LiquibaseAutoConfiguration}.
@ -66,6 +72,29 @@ public class FlywayAutoConfigurationTests {
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
public void testDefaultFlyway() throws Exception {
this.context
@ -113,4 +142,16 @@ public class FlywayAutoConfigurationTests {
PropertyPlaceholderAutoConfiguration.class);
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.suffix=.sql
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.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
@ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() {
return new FancyDataSource();
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix="datasource.secondary")
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`]
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
you can see how to set things up.

Loading…
Cancel
Save