Configure Service Connections for Spring
Page last updated: December 24, 2015
Cloud Foundry provides extensive support for connecting a Spring application to services such as MySQL, PostgreSQL, MongoDB, Redis, and RabbitMQ. In many cases, Cloud Foundry can automatically configure a Spring application without any code changes. For more advanced cases, you can control service connection parameters yourself.
Auto-Reconfiguration
If your Spring application requires services such as a relational database or messaging system, you might be able to deploy your application to Cloud Foundry without changing any code. In this case, Cloud Foundry automatically re-configures the relevant bean definitions to bind them to cloud services.
Cloud Foundry auto-reconfigures applications only if the following items are true for your application:
- Only one service instance of a given service type is bound to the application. In this context, MySQL and PostgreSQL are considered the same service type, relational database, so if both a MySQL and a PostgreSQL service are bound to the application, auto-reconfiguration will not occur.
- Only one bean of a matching type is in the Spring application context. For example, you can have only one bean of type
javax.sql.DataSource
.
With auto-reconfiguration, Cloud Foundry creates the database or connection factory bean itself, using its own values for properties such as host, port, username and so on. For example, if you have a single javax.sql.DataSource
bean in your application context that Cloud Foundry auto-reconfigures and binds to its own database service, Cloud Foundry does not use the username, password and driver URL you originally specified. Instead, it uses its own internal values. This is transparent to the application, which really only cares about having a relational database to which it can write data but does not really care what the specific properties are that created the database. Also note that if you have customized the configuration of a service, such as the pool size or connection properties, Cloud Foundry auto-reconfiguration ignores the customizations.
For more information about auto-reconfiguration of specific services types, see the Service-Specific Details section.
Manual Configuration
Use manual configuration if you have multiple services of a given type or you want to have more control over the configuration than auto-reconfiguration provides.
To use manual configuration, include the spring-cloud
library in your
list of application dependencies.
Update your application Maven pom.xml
or Gradle build.gradle
file to include
dependencies on the
org.springframework.cloud:spring-cloud-spring-service-connector
and
org.springframework.cloud:spring-cloud-cloudfoundry-connector
artifacts.
For example, if you use Maven to build your application, the following pom.xml
snippet shows how to add this dependency.
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-spring-service-connector</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-cloudfoundry-connector</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
</dependencies>
You also need to update your application build file to include the Spring Framework Milestone repository. The following pom.xml
snippet shows how to do this for Maven:
<repositories>
<repository>
<id>repository.springsource.milestone</id>
<name>SpringSource Milestone Repository</name>
<url>http://repo.springsource.org/milestone</url>
</repository>
...
</repositories>
Java Configuration
Typical use of Java config involves extending the AbstractCloudConfig
class and adding methods with the @Bean
annotation to create beans for services. Apps migrating from auto-reconfiguration might first try Scanning for Services until they need more explicit control.
Java config also offers a way to expose application and service properties. Use this for debugging or to create service connectors using a lower-level access.
Creating Service Beans
In the following example, the configuration creates a DataSource
bean connecting to the only relational database service bound to the app. It also creates a MongoDbFactory
bean, again, connecting to the only MongoDB service bound to the app. Check Javadoc for AbstractCloudConfig
for ways to connect to other services.
class CloudConfig extends AbstractCloudConfig {
@Bean
public DataSource inventoryDataSource() {
return connectionFactory().dataSource();
}
... more beans to obtain service connectors
}
The bean names match the method names unless you specify an explicit value to the annotation such as @Bean("inventory-service")
, following Spring’s Java configuration standards.
If you have more than one service of a type bound to the app or want to have an
explicit control over the services to which a bean is bound, you can pass the service names to methods such as dataSource()
and mongoDbFactory()
as follows:
class CloudConfig extends AbstractCloudConfig {
@Bean
public DataSource inventoryDataSource() {
return connectionFactory().dataSource("inventory-db-service");
}
@Bean
public MongoDbFactory documentMongoDbFactory() {
return connectionFactory().mongoDbFactory("document-service");
}
... more beans to obtain service connectors
}
Method such as dataSource()
come in an additional overloaded variant that offer specifying configuration options such as the pooling parameters. See Javadoc for more details.
Connecting to Generic Services
Java config supports access to generic services through the service()
method.
Generic services do not have a directly mapped method. This is typical for a newly introduced service or when connecting to a private service in private PaaS. The generic service()
method follows the same pattern as the
dataSource()
, except it allows supplying the connector type as an additional
parameters.
Scanning for Services
You can scan for each bound service using the @ServiceScan
annotation as shown below. This is conceptually similar to the @ComponentScan annotation in Spring:
@Configuration
@ServiceScan
class CloudConfig {
}
Here, one bean of the appropriate type (DataSource
for a relational database
service, for example) is created. Each created bean will have the id
matching
the corresponding service name. You can then inject such beans using auto-wiring:
@Autowired DataSource inventoryDb;
If the app is bound to more than one services of a type, you can use the @Qualifier
annotation supplying it the name of the service as in the following code:
@Autowired @Qualifier("inventory-db") DataSource inventoryDb;
@Autowired @Qualifier("shipping-db") DataSource shippingDb;
Accessing Service Properties
You can expose raw properties for all services and the app through a bean as follows:
class CloudPropertiesConfig extends AbstractCloudConfig {
@Bean
public Properties cloudProperties() {
return properties();
}
}
Cloud Profile
Spring Framework versions 3.1 and above support bean definition profiles as a way to conditionalize the application configuration so that only specific bean definitions are activated when a certain condition is true. Setting up such profiles makes your application portable to many different environments so that you do not have to manually change the configuration when you deploy it to, for example, your local environment and then to Cloud Foundry.
See the Spring Framework documentation for additional information about using Spring bean definition profiles.
When you deploy a Spring application to Cloud Foundry, Cloud Foundry automatically enables the cloud
profile.
Note: Cloud Foundry auto-reconfiguration requires the Spring application to be version 3.1 or later and include the Spring context JAR. If you are using an earlier version, update your framework or use a custom buildpack.
Profiles in Java Configuration
The @Profile
annotation can be placed on @Configuration
classes in a Spring
application to set conditions under which configuration classes are invoked. By using the default
and cloud
profiles to determine whether the application is running on Cloud Foundry or not, your Java configuration can support both local and cloud deployments using Java configuration classes like these:
public class Configuration {
@Configuration
@Profile("cloud")
static class CloudConfiguration {
@Bean
public DataSource dataSource() {
CloudFactory cloudFactory = new CloudFactory();
Cloud cloud = cloudFactory.getCloud();
String serviceID = cloud.getServiceID();
return cloud.getServiceConnector(serviceID, DataSource.class, null);
}
}
@Configuration
@Profile("default")
static class LocalConfiguration {
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:postgresql://localhost/db");
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUsername("postgres");
dataSource.setPassword("postgres");
return dataSource;
}
}
}
Property Placeholders
Cloud Foundry exposes a number of application and service properties directly into its deployed applications. The properties exposed by Cloud Foundry include basic information about the application, such as its name and the cloud provider, and detailed connection information for all services currently bound to the application.
Service properties generally take one of the following forms:
cloud.services.{service-name}.connection.{property}
cloud.services.{service-name}.{property}
In this form, {service-name}
refers to the name you gave the service when you bound it to your application at deploy time, and {property}
is a field in the credentials section of the VCAP_SERVICES
environment variable.
For example, assume that you created a Postgres service called my-postgres
and then bound it to your application. Assume also that this service exposes credentials in VCAP_SERVICES
as discrete fields. Cloud Foundry exposes the following properties about this service:
cloud.services.my-postgres.connection.hostname
cloud.services.my-postgres.connection.name
cloud.services.my-postgres.connection.password
cloud.services.my-postgres.connection.port
cloud.services.my-postgres.connection.username
cloud.services.my-postgres.plan
cloud.services.my-postgres.type
If the service exposed the credentials as a single uri
field, then the following properties would be set up:
cloud.services.my-postgres.connection.uri
cloud.services.my-postgres.plan
cloud.services.my-postgres.type
For convenience, if you have bound just one service of a given type to your
application, Cloud Foundry creates an alias based on the service type instead of the
service name. For example, if only one MySQL service is bound to an application, the
properties takes the form cloud.services.mysql.connection.{property}
. Cloud
Foundry uses the following aliases in this case:
mysql
postgresql
mongodb
redis
rabbitmq
A Spring application can take advantage of these Cloud Foundry properties using the property placeholder mechanism. For example, assume that you have bound a MySQL service called spring-mysql
to your application. Your application requires a c3p0
connection pool instead of the connection pool provided by Cloud Foundry, but you want to use the same connection properties defined by Cloud Foundry for the MySQL service - in particular the username, password and JDBC URL.
The following table lists all the application properties that Cloud Foundry exposes to deployed applications.
Property | Description |
---|---|
cloud.application.name |
The name provided when the application was pushed to Cloud Foundry. |
cloud.provider.url |
The URL of the cloud hosting the application, such as cloudfoundry.com . |
The service properties that are exposed for each type of service are listed in the Service-Specific Details section.
Service-Specific Details
The following sections describe Spring auto-reconfiguration and manual configuration for the services supported by Cloud Foundry.
MySQL and Postgres
Auto-Reconfiguration
Auto-reconfiguration occurs if Cloud Foundry detects a javax.sql.DataSource
bean in the Spring application context. The following snippet of a Spring application context file shows an example of defining this type of bean which Cloud Foundry will detect and potentially auto-reconfigure:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
The relational database that Cloud Foundry actually uses depends on the service instance you explicitly bind to your application when you deploy it: MySQL or Postgres. Cloud Foundry creates either a commons DBCP or Tomcat datasource depending on which datasource implementation it finds on the classpath.
Cloud Foundry internally generates values for the following properties: driverClassName
, url
, username
, password
, validationQuery
.
Manual Configuration in Java
To configure a database service in Java configuration, create a @Configuration
class with a @Bean
method to return a javax.sql.DataSource
bean. The bean can be created by helper classes in the spring-cloud
library, as shown here:
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
CloudFactory cloudFactory = new CloudFactory();
Cloud cloud = cloudFactory.getCloud();
String serviceID = cloud.getServiceID();
return cloud.getServiceConnector(serviceID, DataSource.class, null);
}
}
MongoDB
Auto-Reconfiguration
You must use Spring Data MongoDB 1.0 M4 or later for auto-reconfiguration to work.
Auto-reconfiguration occurs if Cloud Foundry detects an org.springframework.data.document.mongodb.MongoDbFactory
bean in the Spring application context. The following snippet of a Spring XML application context file shows an example of defining this type of bean which Cloud Foundry will detect and potentially auto-reconfigure:
<mongo:db-factory
id="mongoDbFactory"
dbname="pwdtest"
host="127.0.0.1"
port="1234"
username="test_user"
password="test_pass" />
Cloud Foundry creates a SimpleMongoDbFactory
with its own values for the following properties: host
, port
, username
, password
, dbname
.
Manual Configuration in Java
To configure a MongoDB service in Java configuration, create a @Configuration
class with a @Bean
method to return an org.springframework.data.mongodb.MongoDbFactory
bean from Spring Data MongoDB. The bean can be created by helper classes in the spring-cloud
library, as shown here:
@Configuration
public class MongoConfig {
@Bean
public MongoDbFactory mongoDbFactory() {
CloudFactory cloudFactory = new CloudFactory();
Cloud cloud = cloudFactory.getCloud();
MongoServiceInfo serviceInfo = (MongoServiceInfo) cloud.getServiceInfo("my-mongodb");
String serviceID = serviceInfo.getID();
return cloud.getServiceConnector(serviceID, DataSource.class, null);
}
@Bean
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoDbFactory());
}
}
Redis
Auto-Configuration
You must be using Spring Data Redis 1.0 M4 or later for auto-configuration to work.
Auto-configuration occurs if Cloud Foundry detects a org.springframework.data.redis.connection.RedisConnectionFactory
bean in the Spring application context. The following snippet of a Spring XML application context file shows an example of defining this type of bean which Cloud Foundry will detect and potentially auto-configure:
<bean id="redis"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:hostName="localhost" p:port="6379" />
Cloud Foundry creates a JedisConnectionFactory
with its own values for the following properties: host
, port
, password
. This means that you must package the Jedis JAR in your application. Cloud Foundry does not currently support the JRedis and RJC implementations.
Manual Configuration in Java
To configure a Redis service in Java configuration, create a @Configuration
class with a @Bean
method to return an org.springframework.data.redis.connection.RedisConnectionFactory
bean from Spring Data Redis. The bean can be created by helper classes in the spring-cloud
library, as shown here:
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
CloudFactory cloudFactory = new CloudFactory();
Cloud cloud = cloudFactory.getCloud();
RedisServiceInfo serviceInfo = (RedisServiceInfo) cloud.getServiceInfo("my-redis");
String serviceID = serviceInfo.getID();
return cloud.getServiceConnector(serviceID, DataSource.class, null);
}
@Bean
public RedisTemplate redisTemplate() {
return new StringRedisTemplate(redisConnectionFactory());
}
}
RabbitMQ
Auto-Configuration
You must be using Spring AMQP 1.0 or later for auto-configuration to work. Spring AMQP provides publishing, multi-threaded consumer generation, and message conversion. It also facilitates management of AMQP resources while promoting dependency injection and declarative configuration.
Auto-configuration occurs if Cloud Foundry detects an org.springframework.amqp.rabbit.connection.ConnectionFactory
bean in the Spring application context. The following snippet of a Spring application context file shows an example of defining this type of bean which Cloud Foundry will detect and potentially auto-configure:
<rabbit:connection-factory
id="rabbitConnectionFactory"
host="localhost"
password="testpwd"
port="1238"
username="testuser"
virtual-host="virthost" />
Cloud Foundry creates an org.springframework.amqp.rabbit.connection.CachingConnectionFactory
with its own values for the following properties: host
, virtual-host
, port
, username
, password
.
Manual Configuration in Java
To configure a RabbitMQ service in Java configuration, create a
@Configuration
class with a @Bean
method to return an
org.springframework.amqp.rabbit.connection.ConnectionFactory
bean from the Spring AMQP library. The bean can be created by helper classes in the spring-cloud
library, as shown here:
@Configuration
public class RabbitConfig {
@Bean
public ConnectionFactory rabbitConnectionFactory() {
CloudFactory cloudFactory = new CloudFactory();
Cloud cloud = cloudFactory.getCloud();
AmqpServiceInfo serviceInfo = (AmqpServiceInfo) cloud.getServiceInfo("my-rabbit");
String serviceID = serviceInfo.getID();
return cloud.getServiceConnector(serviceID, ConnectionFactory.class, null);
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}
}