diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index f25fd81c83..24cbb48272 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -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; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayDataSource.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayDataSource.java new file mode 100644 index 0000000000..4a97a90616 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayDataSource.java @@ -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 @Primary. + * + * @author Dave Syer + */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, + ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Qualifier +public @interface FlywayDataSource { + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayProperties.java index 4b0a33f567..e7e6f0de36 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayProperties.java @@ -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 initSqls = Collections.emptyList(); + public void setLocations(List 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 getInitSqls() { + return this.initSqls; + } + + public void setInitSqls(List initSqls) { + this.initSqls = initSqls; + } + + public boolean isCreateDataSource() { + return this.url != null && this.user != null; + } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceBuilder.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceBuilder.java index 521fea24c3..be6c24d1f5 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceBuilder.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceBuilder.java @@ -50,6 +50,8 @@ public class DataSourceBuilder { private ClassLoader classLoader; + private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider(); + private Map properties = new HashMap(); public static DataSourceBuilder create() { @@ -67,10 +69,19 @@ public class DataSourceBuilder { public DataSource build() { Class 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()); } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java index 72a17e23b0..ba969cb41a 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java @@ -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(); + } + + } } diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 39b7f4d401..e8cfd15803 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -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 diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc index 40502bbb81..c8c4ae5f01 100644 --- a/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -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.