Skip to content

Commit 13b6e2d

Browse files
committed
Add ability for user to utilize external DBs for Multi-DB sample
Updated based on code review
1 parent cf285e3 commit 13b6e2d

File tree

7 files changed

+237
-5
lines changed

7 files changed

+237
-5
lines changed

spring-cloud-task-samples/multiple-datasources/README.adoc

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ which one to be used for the Spring Cloud Task repository.
1111

1212
* `MultipleDataSourcesApplication` - the Spring Boot Main Application.
1313
* `SampleCommandLineRunner` - the `CommandLineRunner` implementation for this task. It outputs the number of `DataSource` beans found in the context (should be 2).
14-
* `DataSourceConfiguration` - Configures two `DataSource` beans.
14+
* `EmbeddedDataSourceConfiguration` - Configures two `DataSource` beans using embedded databases.
15+
* `ExternalDataSourceConfiguration` - Configures two `DataSource` beans using external databases.
16+
1517
* `CustomTaskConfigurer` - Uses a Spring `@Qualifier` to specify the correct `DataSource` to use.
1618

1719
== Build:
@@ -21,9 +23,26 @@ which one to be used for the Spring Cloud Task repository.
2123
$ mvn clean package
2224
----
2325

24-
== Run:
26+
== Execute sample using 2 embedded databases (default):
27+
28+
[source,shell,indent=2]
29+
----
30+
$ java -jar target/multiple-datasources-2.3.0-RELEASE.jar
31+
----
32+
33+
== Execute sample using 2 external databases:
2534

35+
Using the `external` profile, users will be able to establish both the default `spring.datasource` data source and a `second.datasource` data source.
36+
For example:
2637
[source,shell,indent=2]
2738
----
28-
$ java -jar target/multiple-datasources-2.2.2.RELEASE.jar
39+
export spring_datasource_url=<your db url>
40+
export spring_datasource_username=<your db user name>
41+
export spring_datasource_password=<your db user password>
42+
export spring_datasource_driverClassName=org.mariadb.jdbc.Driver
43+
export second_datasource_url=jdbc:<your db url>
44+
export second_datasource_username=<your db user name>
45+
export second_datasource_password=<your db user password>
46+
export second_datasource_driverClassName=org.mariadb.jdbc.Driver
47+
java -jar target/multiple-datasources-2.3.0-RELEASE.jar --spring.profiles.active=external
2948
----

spring-cloud-task-samples/multiple-datasources/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
<groupId>org.hsqldb</groupId>
5353
<artifactId>hsqldb</artifactId>
5454
</dependency>
55+
<dependency>
56+
<groupId>org.mariadb.jdbc</groupId>
57+
<artifactId>mariadb-java-client</artifactId>
58+
</dependency>
5559
<dependency>
5660
<groupId>org.springframework.boot</groupId>
5761
<artifactId>spring-boot-starter-test</artifactId>
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,19 @@
2020

2121
import org.springframework.context.annotation.Bean;
2222
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.context.annotation.Profile;
2324
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
2425
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
2526

2627
/**
28+
* Creates two data sources that use embedded databases.
29+
*
2730
* @author Michael Minella
31+
* @author Glenn Renfro
2832
*/
2933
@Configuration
30-
public class DataSourceConfiguration {
34+
@Profile("embedded")
35+
public class EmbeddedDataSourceConfiguration {
3136

3237
@Bean
3338
public DataSource dataSource() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2018-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.configuration;
18+
19+
import javax.sql.DataSource;
20+
21+
import org.springframework.beans.factory.annotation.Qualifier;
22+
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
23+
import org.springframework.boot.context.properties.ConfigurationProperties;
24+
import org.springframework.boot.jdbc.DataSourceBuilder;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.context.annotation.Primary;
28+
import org.springframework.context.annotation.Profile;
29+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
30+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
31+
32+
/**
33+
* Creates two data sources that use external databases.
34+
* @author Glenn Renfro
35+
*/
36+
@Configuration
37+
@Profile("external")
38+
public class ExternalDataSourceConfiguration {
39+
40+
@Bean(name = "springDataSourceProperties")
41+
@ConfigurationProperties("spring.datasource")
42+
@Primary
43+
public DataSourceProperties springDataSourceProperties() {
44+
return new DataSourceProperties();
45+
}
46+
47+
@Bean(name = "secondDataSourceProperties")
48+
@ConfigurationProperties("second.datasource")
49+
public DataSourceProperties myDataSourceProperties() {
50+
return new DataSourceProperties();
51+
}
52+
53+
@Bean(name = "springDataSource")
54+
@Primary
55+
public DataSource dataSource(@Qualifier("springDataSourceProperties")DataSourceProperties springDataSourceProperties) {
56+
return DataSourceBuilder.create().driverClassName(springDataSourceProperties.getDriverClassName()).
57+
url(springDataSourceProperties.getUrl()).
58+
password(springDataSourceProperties.getPassword()).
59+
username(springDataSourceProperties.getUsername()).
60+
build();
61+
}
62+
63+
@Bean
64+
public DataSource secondDataSource(@Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) {
65+
return DataSourceBuilder.create().driverClassName(secondDataSourceProperties.getDriverClassName()).
66+
url(secondDataSourceProperties.getUrl()).
67+
password(secondDataSourceProperties.getPassword()).
68+
username(secondDataSourceProperties.getUsername()).
69+
build();
70+
}
71+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
spring.application.name=Demo Multiple DataSources Task
22
logging.level.org.springframework.cloud.task=DEBUG
3+
4+
spring.profiles.active=embedded

spring-cloud-task-samples/multiple-datasources/src/test/java/io/spring/MultiDataSourcesApplicationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class MultiDataSourcesApplicationTests {
3535
@Test
3636
public void testTimeStampApp(CapturedOutput capturedOutput) throws Exception {
3737

38-
SpringApplication.run(MultipleDataSourcesApplication.class, new String[0]);
38+
SpringApplication.run(MultipleDataSourcesApplication.class, "--spring.profiles.active=embedded");
3939

4040
String output = capturedOutput.toString();
4141

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright 2015-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring;
18+
19+
20+
import java.sql.SQLException;
21+
22+
import org.h2.tools.Server;
23+
import org.junit.jupiter.api.Test;
24+
import org.junit.jupiter.api.extension.ExtendWith;
25+
26+
import org.springframework.boot.SpringApplication;
27+
import org.springframework.boot.test.context.SpringBootTest;
28+
import org.springframework.boot.test.system.CapturedOutput;
29+
import org.springframework.boot.test.system.OutputCaptureExtension;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.test.context.junit.jupiter.SpringExtension;
33+
import org.springframework.util.SocketUtils;
34+
35+
import static org.assertj.core.api.Assertions.assertThat;
36+
37+
/**
38+
* @author Glenn Renfro
39+
*/
40+
@ExtendWith({OutputCaptureExtension.class, SpringExtension.class})
41+
@SpringBootTest(classes = { MultiDataSourcesExternalApplicationTests.TaskLauncherConfiguration.class })
42+
public class MultiDataSourcesExternalApplicationTests {
43+
private final static String DATASOURCE_URL;
44+
45+
private final static String SECOND_DATASOURCE_URL;
46+
47+
private final static String DATASOURCE_USER_NAME = "SA";
48+
49+
private final static String DATASOURCE_USER_PASSWORD = "''";
50+
51+
private final static String DATASOURCE_DRIVER_CLASS_NAME = "org.h2.Driver";
52+
53+
private static int randomPort;
54+
55+
private static int secondRandomPort;
56+
57+
static {
58+
randomPort = SocketUtils.findAvailableTcpPort();
59+
DATASOURCE_URL = "jdbc:h2:tcp://localhost:" + randomPort
60+
+ "/mem:dataflow;DB_CLOSE_DELAY=-1;" + "DB_CLOSE_ON_EXIT=FALSE";
61+
secondRandomPort = SocketUtils.findAvailableTcpPort();
62+
SECOND_DATASOURCE_URL = "jdbc:h2:tcp://localhost:" + randomPort
63+
+ "/mem:dataflow;DB_CLOSE_DELAY=-1;" + "DB_CLOSE_ON_EXIT=FALSE";
64+
}
65+
66+
67+
@Test
68+
public void testTimeStampApp(CapturedOutput capturedOutput) throws Exception {
69+
70+
SpringApplication.run(MultipleDataSourcesApplication.class, "--spring.profiles.active=external",
71+
"--spring.datasource.url=" + DATASOURCE_URL,
72+
"--spring.datasource.username=" + DATASOURCE_USER_NAME,
73+
"--spring.datasource.password=" + DATASOURCE_USER_PASSWORD,
74+
"--spring.datasource.driverClassName=" + DATASOURCE_DRIVER_CLASS_NAME,
75+
"--second.datasource.url=" + SECOND_DATASOURCE_URL,
76+
"--second.datasource.username=" + DATASOURCE_USER_NAME,
77+
"--second.datasource.password=" + DATASOURCE_USER_PASSWORD,
78+
"--second.datasource.driverClassName=" + DATASOURCE_DRIVER_CLASS_NAME);
79+
80+
String output = capturedOutput.toString();
81+
82+
assertThat(output.contains("There are 2 DataSources within this application"))
83+
.as("Unable to find CommandLineRunner output: " + output).isTrue();
84+
assertThat(output.contains("Creating: TaskExecution{"))
85+
.as("Unable to find start task message: " + output).isTrue();
86+
assertThat(output.contains("Updating: TaskExecution"))
87+
.as("Unable to find update task message: " + output).isTrue();
88+
}
89+
90+
@Configuration
91+
public static class TaskLauncherConfiguration {
92+
93+
private static Server defaultServer;
94+
95+
private static Server secondServer;
96+
97+
@Bean
98+
public Server initH2TCPServer() {
99+
Server server = null;
100+
try {
101+
if (defaultServer == null) {
102+
server = Server.createTcpServer("-ifNotExists", "-tcp",
103+
"-tcpAllowOthers", "-tcpPort", String.valueOf(randomPort))
104+
.start();
105+
defaultServer = server;
106+
}
107+
}
108+
catch (SQLException e) {
109+
throw new IllegalStateException(e);
110+
}
111+
return defaultServer;
112+
}
113+
114+
@Bean
115+
public Server initSecondH2TCPServer() {
116+
Server server = null;
117+
try {
118+
if (secondServer == null) {
119+
server = Server.createTcpServer("-ifNotExists", "-tcp",
120+
"-tcpAllowOthers", "-tcpPort", String.valueOf(secondRandomPort))
121+
.start();
122+
secondServer = server;
123+
}
124+
}
125+
catch (SQLException e) {
126+
throw new IllegalStateException(e);
127+
}
128+
return secondServer;
129+
}
130+
}
131+
}

0 commit comments

Comments
 (0)