Commit 7c8fc637 authored by Scott Frederick's avatar Scott Frederick

Let Spring Boot auto-configure connections for local profiles. Remove…

Let Spring Boot auto-configure connections for local profiles. Remove commons-dbcp2 dependency and let Boot default the DataSource implementation.
parent f6f54f40
......@@ -29,13 +29,12 @@ $ java -jar -Dspring.profiles.active=<profile> build/libs/spring-music.jar
where `<profile>` is one of the following values:
* `in-memory` (no external database required)
* `mysql`
* `postgres`
* `mongodb`
* `redis`
If no profile is provided, `in-memory` will be used. If any other profile is provided, the appropriate database server must be started separately. The application will use the host name `localhost` and the default port to connect to the database. The connection parameters can be configured by setting the appropriate [Spring Boot properties](http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html).
If no profile is provided, an in-memory relational database will be used. If any other profile is provided, the appropriate database server must be started separately. Spring Boot will auto-configure a connection to the database using it's auto-configuration defaults. The connection parameters can be configured by setting the appropriate [Spring Boot properties](http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html).
If more than one of these profiles is provided, the application will throw an exception and fail to start.
......@@ -43,7 +42,7 @@ If more than one of these profiles is provided, the application will throw an ex
When running on Cloud Foundry, the application will detect the type of database service bound to the application (if any). If a service of one of the supported types (MySQL, Postgres, Oracle, MongoDB, or Redis) is bound to the app, the appropriate Spring profile will be configured to use the database service. The connection strings and credentials needed to use the service will be extracted from the Cloud Foundry environment.
If no bound services are found containing any of these values in the name, then the `in-memory` profile will be used.
If no bound services are found containing any of these values in the name, an in-memory relational database will be used.
If more than one service containing any of these values is bound to the application, the application will throw an exception and fail to start.
......
......@@ -46,7 +46,6 @@ dependencies {
compile "org.springframework.cloud:spring-cloud-cloudfoundry-connector:${springCloudConnectorsVersion}"
// JPA Persistence
compile "org.apache.commons:commons-dbcp2"
runtime "com.h2database:h2"
runtime "mysql:mysql-connector-java"
runtime "org.postgresql:postgresql"
......
......@@ -31,15 +31,16 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SpringApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Log logger = LogFactory.getLog(SpringApplicationContextInitializer.class);
private static final Map<Class<? extends ServiceInfo>, String> serviceTypeToProfileName = new HashMap<>();
private static final List<String> validLocalProfiles = Arrays.asList("mysql", "postgres", "mongodb", "redis");
private static final String IN_MEMORY_PROFILE = "in-memory";
private static final List<String> validLocalProfiles =
Arrays.asList("mysql", "postgres", "sqlserver", "oracle", "mongodb", "redis");
static {
serviceTypeToProfileName.put(MongoServiceInfo.class, "mongodb");
......@@ -56,24 +57,16 @@ public class SpringApplicationContextInitializer implements ApplicationContextIn
ConfigurableEnvironment appEnvironment = applicationContext.getEnvironment();
String[] persistenceProfiles = getCloudProfile(cloud);
if (persistenceProfiles == null) {
persistenceProfiles = getActiveProfile(appEnvironment);
}
if (persistenceProfiles == null) {
persistenceProfiles = new String[] { IN_MEMORY_PROFILE };
}
validateActiveProfiles(appEnvironment);
for (String persistenceProfile : persistenceProfiles) {
appEnvironment.addActiveProfile(persistenceProfile);
}
addCloudProfile(cloud, appEnvironment);
excludeAutoConfiguration(appEnvironment);
}
private String[] getCloudProfile(Cloud cloud) {
private void addCloudProfile(Cloud cloud, ConfigurableEnvironment appEnvironment) {
if (cloud == null) {
return null;
return;
}
List<String> profiles = new ArrayList<>();
......@@ -97,10 +90,9 @@ public class SpringApplicationContextInitializer implements ApplicationContextIn
}
if (profiles.size() > 0) {
return createProfileNames(profiles.get(0), "cloud");
appEnvironment.addActiveProfile(profiles.get(0));
appEnvironment.addActiveProfile(profiles.get(0) + "-cloud");
}
return null;
}
private Cloud getCloud() {
......@@ -112,14 +104,10 @@ public class SpringApplicationContextInitializer implements ApplicationContextIn
}
}
private String[] getActiveProfile(ConfigurableEnvironment appEnvironment) {
List<String> serviceProfiles = new ArrayList<>();
for (String profile : appEnvironment.getActiveProfiles()) {
if (validLocalProfiles.contains(profile)) {
serviceProfiles.add(profile);
}
}
private void validateActiveProfiles(ConfigurableEnvironment appEnvironment) {
List<String> serviceProfiles = Stream.of(appEnvironment.getActiveProfiles())
.filter(validLocalProfiles::contains)
.collect(Collectors.toList());
if (serviceProfiles.size() > 1) {
throw new IllegalStateException("Only one active Spring profile may be set among the following: " +
......@@ -127,18 +115,6 @@ public class SpringApplicationContextInitializer implements ApplicationContextIn
"These profiles are active: [" +
StringUtils.collectionToCommaDelimitedString(serviceProfiles) + "]");
}
if (serviceProfiles.size() > 0) {
return createProfileNames(serviceProfiles.get(0), "local");
}
return null;
}
private String[] createProfileNames(String baseName, String suffix) {
String[] profileNames = {baseName, baseName + "-" + suffix};
logger.info("Setting profile names: " + StringUtils.arrayToCommaDelimitedString(profileNames));
return profileNames;
}
private void excludeAutoConfiguration(ConfigurableEnvironment environment) {
......
package org.cloudfoundry.samples.music.config.data;
import org.apache.commons.dbcp2.BasicDataSource;
import javax.sql.DataSource;
public class AbstractLocalDataSourceConfig {
protected DataSource createDataSource(String jdbcUrl, String driverClass, String userName, String password) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl(jdbcUrl);
dataSource.setDriverClassName(driverClass);
dataSource.setUsername(userName);
dataSource.setPassword(password);
return dataSource;
}
}
package org.cloudfoundry.samples.music.config.data;
import com.mongodb.MongoClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
@Configuration
@Profile("mongodb-local")
public class MongoLocalConfig {
@Bean
public MongoDbFactory mongoDbFactory() {
return new SimpleMongoDbFactory(new MongoClient(), "music");
}
}
package org.cloudfoundry.samples.music.config.data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
@Configuration
@Profile("mysql-local")
public class MySqlLocalDataSourceConfig extends AbstractLocalDataSourceConfig {
@Bean
public DataSource dataSource() {
return createDataSource("jdbc:mysql://localhost/music", "com.mysql.jdbc.Driver", "", "");
}
}
package org.cloudfoundry.samples.music.config.data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
@Configuration
@Profile("postgres-local")
public class PostgresLocalDataSourceConfig extends AbstractLocalDataSourceConfig {
@Bean
public DataSource dataSource() {
return createDataSource("jdbc:postgresql://localhost/music",
"org.postgresql.Driver", "postgres", "postgres");
}
}
package org.cloudfoundry.samples.music.config.data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
@Configuration
@Profile("redis-local")
public class RedisLocalConfig {
@Bean
public RedisConnectionFactory redisConnection() {
return new JedisConnectionFactory();
}
}
......@@ -6,6 +6,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
@Profile({"in-memory", "mysql", "postgres", "oracle", "sqlserver"})
@Profile({"!mongodb", "!redis"})
public interface JpaAlbumRepository extends JpaRepository<Album, String> {
}
......@@ -11,7 +11,25 @@ management:
---
spring:
profiles: mysql
datasource:
url: "jdbc:mysql://localhost/music"
driver-class-name: com.mysql.jdbc.Driver
username:
password:
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL55Dialect
---
spring:
profiles: postgres
datasource:
url: "jdbc:postgresql://localhost/music"
driver-class-name: org.postgresql.Driver
username: postgres
password:
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.ProgressDialect
......@@ -3,13 +3,11 @@ package org.cloudfoundry.samples.music;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest()
@ActiveProfiles("in-memory")
public class ApplicationTests {
@Test
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment