Автор Дэйв Сайер в весеннем блоге
В этой статье мы рассмотрим, как связать приложение Spring Boot со службами данных (JDBC, NoSQL, обмен сообщениями и т. Д.), А также различные источники поведения по умолчанию и автоматического поведения в Cloud Foundry , предоставив некоторые рекомендации о том, какие из них использовать и какие будут быть активным при каких условиях. Spring Boot предоставляет множество функций автоконфигурации и внешнего связывания, некоторые из которых относятся к Cloud Foundry, а многие — нет. Spring Cloud Connectors — это библиотека, которую вы можете использовать в своем приложении, если вы хотите создавать свои собственные компоненты программно, но она сама по себе не делает ничего «волшебного». И, наконец, есть пакет Java Foundry Cloud Foundry. которая имеет функцию «автоматической реконфигурации», которая пытается облегчить бремя переноса простых приложений в облако. Ключ к правильной настройке сервисов промежуточного программного обеспечения, таких как JDBC, AMQP или Mongo, заключается в том, чтобы понять, что предоставляет каждый из этих инструментов, как они влияют друг на друга во время выполнения, а также и включать и выключать их части. Цель должна состоять в плавном переходе от локального выполнения приложения на рабочем столе разработчика к тестовой среде в Cloud Foundry и, в конечном итоге, к производству в Cloud Foundry (или иным образом) без изменений в исходном коде или упаковке, согласно двенадцатикратному фактору. руководство по применению .
Существует несколько простых исходных кодов, сопровождающих эту статью. Чтобы использовать его, вы можете клонировать репозиторий и импортировать его в вашу любимую IDE. Вам нужно будет удалить две зависимости из всего проекта, чтобы добраться до той же точки, где мы начнем обсуждать конкретные примеры кода, а именно spring-boot-starter-cloud-connectors
и auto-reconfiguration
.
Примечание: текущие координаты для всех библиотек обсуждаются являются
org.springframework.boot:spring-boot-*:1.2.3.RELEASE
,org.springframework.boot:spring-cloud-*-connector:1.1.1.RELEASE
,org.cloudfoundry:auto-reconfiguration:1.7.0.RELEASE
.СОВЕТ: Исходный код в github включает в себя
docker-compose.yml
файл ( документы здесь ). Вы можете использовать это для создания локальной базы данных MySQL, если у вас ее еще нет. На самом деле он не нужен для выполнения большей части приведенного ниже кода, но может оказаться полезным проверить, действительно ли он работает.
Изюминка для нетерпеливых
Если вы хотите пропустить детали, и все, что вам нужно, это рецепт для локального запуска с H2 и в облаке с MySQL, тогда начните здесь и прочитайте остальное позже, когда вы хотите понять более подробно. (Аналогичные параметры существуют для других служб данных, таких как RabbitMQ, Redis, Mongo и т. Д.)
Ваш первый и DataSource
самый простой вариант — просто ничего не делать: вообще не определять a, а ставить H2 на путь к классам. Spring Boot создаст встроенный H2 DataSource
для вас, когда вы работаете локально. Пакет компоновки Cloud Foundry определит привязку службы базы данных и создаст ее DataSource
для вас при запуске в облаке. Если вы также добавите Spring Cloud Connectors, ваше приложение будет работать и на других облачных платформах, если вы включите соединитель. Это может быть достаточно, если вы просто хотите, чтобы что-то работало.
Если вы хотите запустить серьезное приложение в рабочей среде, вы можете настроить некоторые параметры пула соединений (например, размер пула, различные таймауты, важный тест на флаг заимствования). В этом случае автоматическая реконфигурация buildpack DataSource
не будет соответствовать вашим требованиям, и вам нужно будет выбрать альтернативу, и есть ряд более или менее разумных вариантов.
Наилучшим выбором, вероятно, является создание DataSource
явно использующих Spring Cloud Connectors , но защищенных «облачным» профилем:
@Configuration @Profile("cloud") public class DataSourceConfiguration { @Bean public Cloud cloud() { return new CloudFactory().getCloud(); } @Bean @ConfigurationProperties(DataSourceProperties.PREFIX) public DataSource dataSource() { return cloud().getSingletonServiceConnector(DataSourceclass, null); } }
Вы можете использовать spring.datasource.*
свойства (например, application.properties
или его версию для конкретного профиля), чтобы установить дополнительные свойства во время выполнения. «Облачный» профиль автоматически активируется для вас пакетом buildpack.
Теперь о деталях. Нам нужно составить представление о том, что происходит в вашем приложении во время выполнения, чтобы мы могли из этого узнать, как сделать разумный выбор для настройки служб данных.
Слои автоконфигурации
Давайте возьмем простое приложение с DataSource
(аналогичные соображения применимы к RabbitMQ, Mongo, Redis):
@SpringBootApplication public class CloudApplication { @Autowired private DataSource dataSource; public static void main(String[] args) { SpringApplication.run(CloudApplication.class, args); } }
Это полное приложение: DataSource
может быть @Autowired
потому, что оно создано для нас Spring Boot. Детали DataSource
(конкретный класс, драйвер JDBC, URL-адрес соединения и т. Д.) Зависят от того, что находится на пути к классам. Предположим, что приложение использует Spring JDBC через spring-boot-starter-jdbc
(или spring-boot-starter-data-jpa
), поэтому у него есть DataSource
реализация, доступная от Tomcat (даже если это не веб-приложение), и это то, что использует Spring Boot.
Посмотрите, что происходит, когда:
-
Classpath содержит H2 (только) в дополнение к стартерам:
DataSource
это высокопроизводительный пул Tomcat,DataSourceAutoConfiguration
который подключается к базе данных «testdb» в памяти. -
Classpath содержит H2 и MySQL:
DataSource
по-прежнему H2 (так же, как и раньше), потому что мы не предоставили никакой дополнительной конфигурации для MySQL, и Spring Boot не может угадать учетные данные для подключения. -
Добавьте
spring-boot-starter-cloud-connectors
к classpath: без изменений,DataSource
потому что Spring Cloud Connectors не обнаруживают, что они работают на облачной платформе. Все провайдеры, которые идут с самого начала, ищут конкретные переменные среды, которые они не найдут, если вы не установите их или не запустите приложение в Cloud Foundry, Heroku и т. Д. -
Запустите приложение в «облачном» профиле с
spring.profiles.active=cloud
: без изменений вDataSource
, но это одна из вещей, которую делает сборка Java , когда ваше приложение работает в Cloud Foundry. -
Запустите «облачный» профиль и предоставьте некоторые переменные среды для имитации работы в Cloud Foundry и привязки к службе MySQL:
VCAP_APPLICATION={"name":"application","instance_id":"FOO"} VCAP_SERVICES={"mysql":[{"name":"mysql","tags":["mysql"],"credentials":{"uri":"mysql://root:root@localhost/test"}}]}
(«теги» предоставляют подсказку, что мы хотим создать MySQL
DataSource
, «uri» предоставляет местоположение, а «имя» становится идентификатором компонента).DataSource
Теперь использует MySQL с учетными данными , поставляемыхVCAP_*
переменных окружения. Spring Boot имеет некоторую автоконфигурацию для коннекторов, поэтому если вы посмотрите на bean-компоненты в своем приложении, вы увидитеCloudFactory
bean-компонент, а такжеDataSource
bean-компонент (с идентификатором «mysql»). Автоконфигурация эквивалентно добавлению@ServiceScan
к конфигурации вашего приложения. Он активен только в том случае, если ваше приложение работает в «облачном» профиле, и только в том случае, если@Bean
тип не существуетCloud
и флаг конфигурацииspring.cloud.enabled
не «ложен». -
Добавьте JAR «автореконфигурации» из пакета сборки Java (координаты Maven
org.cloudfoundry:auto-reconfiguration:1.7.0.RELEASE
). Вы можете добавить его как локальную зависимость для имитации запуска приложения в Cloud Foundry, но это не будет нормально делать с реальным приложением (это просто для экспериментов с автоконфигурацией). JAR с автоматической реконфигурацией теперь имеет все, что нужно для созданияDataSource
, но его (пока) нет, потому что он обнаруживает, что у вас уже есть бин типаCloudFactory
, который был добавлен Spring Boot. -
Удалите явный «облачный» профиль. Профиль будет по-прежнему активен при запуске приложения, поскольку JAR-файл с автоматической реконфигурацией снова добавляет его. По-прежнему нет изменений,
DataSource
потому что Spring Boot создал его для вас через@ServiceScan
. -
Удалите
spring-boot-starter-cloud-connectors
зависимость, чтобы Spring Boot прекратил созданиеCloudFactory
. JAR с автоматической реконфигурацией фактически имеет свою собственную копию Spring Cloud Connectors (все классы с разными именами пакетов), и теперь он использует их для созданияDataSource
(в aBeanFactoryPostProcessor
). Автоконфигурированный Spring BootDataSource
заменяется на тот, который связывается с MySQL черезVCAP_SERVICES
. Нет никакого контроля над свойствами пула, но он все еще использует пул Tomcat, если он доступен (без поддержки Hikari или DBCP2). -
Удалите автоконфигурационный JAR и
DataSource
возвращается к H2.
СОВЕТ: используйте ленточные пускатели и приводы,
endpoints.health.sensitive=false
чтобыDataSource
быстро проверить «/ здоровье». Вы также можете использовать конечные точки «/ beans», «/ env» и «/ autoconfig», чтобы увидеть, что происходит в автоконфигурации и почему.ПРИМЕЧАНИЕ. Запуск в Cloud Foundry или включение JAR с автоматической реконфигурацией в classpath локально активируют профиль «cloud» (по той же причине). В
VCAP_*
Env вары являются то , что делает Spring Cloud и / или автоматической реконфигурации JAR создать бобы.ПРИМЕЧАНИЕ. URL в
VCAP_SERVICES
действительности не является схемой «jdbc», которая должна быть обязательной для соединений JDBC. Это, однако, формат, в котором Cloud Foundry обычно представляет его, потому что он работает почти для всех языков, кроме Java. Spring Cloud Connectors или автоматическая реконфигурация buildpack, если они создаютDataSource
, преобразуют его вjdbc:*
URL для вас.ПРИМЕЧАНИЕ. URL-адрес MySQL также содержит учетные данные пользователя и имя базы данных, действительные для контейнера Docker, созданного
docker-compose.yml
в примере исходного кода. Если у вас есть локальный сервер MySQL с другими учетными данными, вы можете заменить их.СОВЕТ: Если вы используете локальный сервер MySQL и хотите убедиться, что он подключен, вы можете использовать конечную точку «/ health» из Spring Boot Actuator (уже включена в пример кода). Или вы можете создать
schema-mysql.sql
файл в корне пути к классам и поместить в него простой запрос поддержки активности (напримерSELECT 1
). Spring Boot запустит это при запуске, так что если приложение запускается успешно, вы правильно настроили базу данных.
JAR с автоматической реконфигурацией всегда находится на пути к классам в Cloud Foundry (по умолчанию), но он отменяет создание любого, DataSource
если находит объект org.springframework.cloud.CloudFactory
EJB (который предоставляется Spring Boot, если CloudAutoConfiguration
он активен). Таким образом, чистый эффект добавления его в classpath, если коннекторы также присутствуют в приложении Spring Boot, заключается только в том, чтобы включить «облачный» профиль. Вы можете видеть, что принимаете решение пропустить автоматическую реконфигурацию в журналах приложения при запуске:
015-04-14 15:11:11.765 INFO 12727 --- [ main] urceCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type javax.sql.DataSource 2015-04-14 15:11:57.650 INFO 12727 --- [ main] ongoCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type org.springframework.data.mongodb.MongoDbFactory 2015-04-14 15:11:57.650 INFO 12727 --- [ main] bbitCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type org.springframework.amqp.rabbit.connection.ConnectionFactory 2015-04-14 15:11:57.651 INFO 12727 --- [ main] edisCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type org.springframework.data.redis.connection.RedisConnectionFactory ... etc.
Создайте свой собственный источник данных
В последнем разделе рассмотрены большинство важных функций автоконфигурации в различных библиотеках. Если вы хотите взять контроль над собой, вы можете начать с создания собственного экземпляра DataSource
. Вы можете сделать это, например, используя DataSourceBuilder
удобный класс, который входит в состав Spring Boot (он выбирает реализацию на основе пути к классам):
@SpringBootApplication public class CloudApplication { @Bean public DataSource dataSource() { return DataSourceBuilder.create().build(); } ... }
Как DataSource
мы определили, он бесполезен, потому что у него нет URL-адреса подключения или учетных данных, но это легко исправить. Давайте запустим это приложение, как если бы оно было в Cloud Foundry: с VCAP_*
переменными среды и JAR с автоматической реконфигурацией, но без соединителей Spring Cloud на пути к классам и без явного «облачного» профиля. Buildpack активирует «облачный» профиль, создает DataSource
и привязывает его к VCAP_SERVICES
. Как уже было кратко описано, он полностью удаляет ваш файл DataSource
и заменяет его зарегистрированным вручную синглтоном (который не отображается в конечной точке «/ beans» в Spring Boot).
Теперь добавьте Spring Cloud Connectors обратно в путь к классам приложения и посмотрите, что произойдет, когда вы запустите его снова. Это на самом деле не при запуске! Что случилось? @ServiceScan
(От коннекторов) идет и выглядит для связанных услуг, а также создают определения боба для них. Это немного похоже на buildpack-пакет, но отличается тем, что он не пытается заменить существующие определения бинов того же типа. Таким образом, вы получаете ошибку автопроводки, потому что есть 2 DataSources
и нет способа выбрать один для внедрения в ваше приложение в различных местах, где это необходимо.
Чтобы это исправить, нам придется взять на себя управление облачными коннекторами (или просто не использовать их).
Использование CloudFactory для создания источника данных
Вы можете отключить автоконфигурацию Spring Boot и автореконфигурирование Java buildpack, создав собственный Cloud
экземпляр в виде @Bean
:
@Bean public Cloud cloud() { return new CloudFactory().getCloud(); } @Bean @ConfigurationProperties(DataSourceProperties.PREFIX) public DataSource dataSource() { return cloud().getSingletonServiceConnector(DataSource.class, null); }
Плюсы: автоконфигурация коннекторов в Spring Boot отключена, поэтому есть только один DataSource
. Его можно настроить с application.properties
помощью spring.datasource.*
свойств через Spring Boot User Guide .
Минусы: он не работает без VCAP_*
переменных среды (или какой-либо другой облачной платформы). Он также полагается на то, что пользователь не забывает указывать Cloud
как a @Bean
, чтобы отключить автоконфигурацию.
Резюме: мы все еще не в удобном месте (приложение, которое не запускается без сложной обработки переменных среды, практически не используется).
Двойной запуск: локально с H2, в облаке с MySQL
В Spring Cloud Connectors есть опция локального файла конфигурации, поэтому вам не нужно быть на реальной облачной платформе, чтобы использовать их, но это неудобно в настройке, несмотря на то, что вы работаете на платформе, и вам также нужно как-то отключить его, когда вы находитесь в реальной облачной платформе. Последний пункт действительно важный, потому что в конечном итоге вам нужен локальный файл для локального запуска, но только локальный, и он не может быть упакован с остальным кодом приложения (например, нарушает рекомендации по 12 факторам).
Поэтому, чтобы двигаться дальше с нашим явным @Bean
определением, вероятно, лучше придерживаться основных функций Spring и Spring Boot, например, используя профиль «cloud» для защиты явного создания DataSource
:
@Configuration @Profile("cloud") public class DataSourceConfiguration { @Bean public Cloud cloud() { return new CloudFactory().getCloud(); } @Bean @ConfigurationProperties(DataSourceProperties.PREFIX) public DataSource dataSource() { return cloud().getSingletonServiceConnector(DataSource.class, null); } }
With this in place we have a solution that works smoothly both locally and in Cloud Foundry. Locally Spring Boot will create a DataSource
with an H2 embedded database. In Cloud Foundry it will bind to a singleton service of type DataSource
and switch off the autconfigured one from Spring Boot. It also has the benefit of working with any platform supported by Spring Cloud Connectors, so the same code will run on Heroku and Cloud Foundry, for instance. Because of the @ConfigurationProperties
you can bind additional configuration to the DataSource
to tweak connection pool properties and things like that if you need to in production.
NOTE: We have been using MySQL as an example database server, but actually PostgreSQL is at least as compelling a choice if not more. When paired with H2 locally, for instance, you can put H2 into its “Postgres compatibility” mode and use the same SQL in both environments.
Manually Creating a Local and a Cloud DataSource
If you like creating DataSource
beans, and you want to do it both locally and in the cloud, you could use 2 profiles (“cloud” and “local”), for example. But then you would have to find a way to activate the “local” profile by default when not in the cloud. There is already a way to do that built into Spring because there is always a default profile called “default” (by default). So this should work:
@Configuration @Profile("default") // or "!cloud" public class LocalDataSourceConfiguration { @Bean @ConfigurationProperties(DataSourceProperties.PREFIX) public DataSource dataSource() { return DataSourceBuilder.create().build(); } } @Configuration @Profile("cloud") public class CloudDataSourceConfiguration { @Bean public Cloud cloud() { return new CloudFactory().getCloud(); } @Bean @ConfigurationProperties(DataSourceProperties.PREFIX) public DataSource dataSource() { return cloud().getSingletonServiceConnector(DataSource.class, null); } }
The “default” DataSource
is actually identical to the autoconfigured one in this simple example, so you wouldn’t do this unless you needed to, e.g. to create a custom concreteDataSource
of a type not supported by Spring Boot. You might think it’s all getting a bit complicated, but in fact Spring Boot is not making it any harder, we are just dealing with the consequences of needing to control the DataSource
construction in 2 environments.
Using a Non-Embedded Database Locally
If you don’t want to use H2 or any in-memory database locally, then you can’t really avoid having to configure it (Spring Boot can guess a lot from the URL, but it will need that at least). So at a minimum you need to set some spring.datasource.*
properties (the URL for instance). That that isn’t hard to do, and you can easily set different values in different environments using additional profiles, but as soon as you do that you need to switch off the default values when you go into the cloud. To do that you could define thespring.datasource.*
properties in a profile-specific file (or document in YAML) for the “default” profile, e.g. application-default.properties
, and these will not be used in the “cloud” profile.
A Purely Declarative Approach
If you prefer not to write Java code, or don’t want to use Spring Cloud Connectors, you might want to try and use Spring Boot autoconfiguration and external properties (or YAML) files for everything. For example Spring Boot creates a DataSource
for you if it finds the right stuff on the classpath, and it can be completely controlled through application.properties
, including all the granular features on the DataSource
that you need in production (like pool sizes and validation queries). So all you need is a way to discover the location and credentials for the service from the environment. The buildpack translates Cloud Foundry VCAP_*
environment variables into usable property sources in the Spring Environment
. Thus, for instance, a DataSource
configuration might look like this:
spring.datasource.url: ${cloud.services.mysql.connection.jdbcurl:jdbc:h2:mem:testdb} spring.datasource.username: ${cloud.services.mysql.connection.username:sa} spring.datasource.password: ${cloud.services.mysql.connection.password:} spring.datasource.testOnBorrow: true
The “mysql” part of the property names is the service name in Cloud Foundry (so it is set by the user). And of course the same pattern applies to all kinds of services, not just a JDBCDataSource
. Generally speaking it is good practice to use external configuration and in particular @ConfigurationProperties
since they allow maximum flexibility, for instance to override using System properties or environment variables at runtime.
Note: similar features are provided by Spring Boot, which provides
vcap.services.*
instead ofcloud.services.*
, so you actually end up with more than one way to do this. However, the JDBC urls are not available from thevcap.services.*
properties (non-JDBC services work fine with tthe correspondingvcap.services.*credentials.url
).
One limitation of this approach is it doesn’t apply if the application needs to configure beans that are not provided by Spring Boot out of the box (e.g. if you need 2 DataSources
), in which case you have to write Java code anyway, and may or may not choose to use properties files to parameterize it.
Before you try this yourself, though, beware that actually it doesn’t work unless you also disable the buildpack auto-reconfiguration (and Spring Cloud Connectors if they are on the classpath). If you don’t do that, then they create a new DataSource
for you and Spring Boot cannot bind it to your properties file. Thus even for this declarative approach, you end up needing an explicit @Bean
definition, and you need this part of your “cloud” profile configuration:
@Configuration @Profile("cloud") public class CloudDataSourceConfiguration { @Bean public Cloud cloud() { return new CloudFactory().getCloud(); } }
This is purely to switch off the buildpack auto-reconfiguration (and the Spring Boot autoconfiguration, but that could have been disabled with a properties file entry).
Mixed Declarative and Explicit Bean Definition
You can also mix the two approaches: declare a single @Bean
definition so that you control the construction of the object, but bind additional configuration to it using@ConfigurationProperties
(and do the same locally and in Cloud Foundry). Example:
@Configuration public class LocalDataSourceConfiguration { @Bean @ConfigurationProperties(DataSourceProperties.PREFIX) public DataSource dataSource() { return DataSourceBuilder.create().build(); } }
(where the DataSourceBuilder
would be replaced with whatever fancy logic you need for your use case). And the application.properties
would be the same as above, with whatever additional properties you need for your production settings.
A Third Way: Discover the Credentials and Bind Manually
Another approach that lends itself to platform and environment independence is to declare explicit bean definitions for the @ConfigurationProperties
beans that Spring Boot uses to bind its autoconfigured connectors. For instance, to set the default values for a DataSource
you can declare a @Bean
of type DataSourceProperties
:
@Bean @Primary public DataSourceProperties dataSourceProperties() { DataSourceProperties properties = new DataSourceProperties(); properties.setInitialize(false); return properties; }
This sets a default value for the “initialize” flag, and allows other properties to be bound fromapplication.properties
(or other external properties). Combine this with the Spring Cloud Connectors and you can control the binding of the credentials when a cloud service is detected:
@Autowired(required="false") Cloud cloud; @Bean @Primary public DataSourceProperties dataSourceProperties() { DataSourceProperties properties = new DataSourceProperties(); properties.setInitialize(false); if (cloud != null) { List<ServiceInfo> infos = cloud.getServiceInfos(RelationalServiceInfo.class); if (infos.size()==1) { RelationalServiceInfo info = (RelationalServiceInfo) infos.get(0); properties.setUrl(info.getJdbcUrl()); properties.setUsername(info.getUserName()); properties.setPassword(info.getPassword()); } } return properties; }
and you still need to define the Cloud
bean in the “cloud” profile. It ends up being quite a lot of code, and is quite unnecessary in this simple use case, but might be handy if you have more complicated bindings, or need to implement some logic to choose a DataSource
at runtime.
Spring Boot has similar *Properties
beans for the other middleware you might commonly use (e.g. RabbitProperties
, RedisProperties
, MongoProperties
). An instance of such a bean marked as @Primary
is enough to reset the defaults for the autoconfigured connector.
Deploying to Multiple Cloud Platforms
So far, we have concentrated on Cloud Foundry as the only cloud platform in which to deploy the application. One of the nice features of Spring Cloud Connectors is that it supports other platforms, either out of the box or as extension points. Thespring-boot-starter-cloud-connectors
even includes Heroku support. If you do nothing at all, and rely on the autoconfiguration (the lazy programmer’s approach), then your application will be deployable in all clouds where you have a connector on the classpath (i.e. Cloud Foundry and Heroku if you use the starter). If you take the explicit @Bean
approach then you need to ensure that the “cloud” profile is active in the non-Cloud Foundry platforms, e.g. through an environment variable. And if you use the purely declarative approach (or any combination involving properties files) you need to activate the “cloud” profile and probably also another profile specific to your platform, so that the right properties files end up in theEnvironment
at runtime.
Summary of Autoconfiguration and Provided Behaviour
-
Spring Boot provides
DataSource
(also RabbitMQ or RedisConnectionFactory
, Mongo etc.) if it finds all the right stuff on the classpath. Using the “spring-boot-starter-*” dependencies is sufficient to activate the behaviour. -
Spring Boot also provides an autowirable
CloudFactory
if it finds Spring Cloud Connectors on the classpath (but switches off only if it finds a@Bean
of typeCloud
). -
The
CloudAutoConfiguration
in Spring Boot also effectively adds a@CloudScan
to your application, which you would want to switch off if you ever needed to create your ownDataSource
(or similar). -
The Cloud Foundry Java buildpack detects a Spring Boot application and activates the “cloud” profile, unless it is already active. Adding the buildpack auto-reconfiguration JAR does the same thing if you want to try it locally.
-
Through the auto-reconfiguration JAR, the buildpack also kicks in and creates a
DataSource
(ditto RabbitMQ, Redis, Mongo etc.) if it does not find aCloudFactory
bean or aCloud
bean (amongst others). So including Spring Cloud Connectors in a Spring Boot application switches off this part of the “auto-reconfiguration” behaviour (the bean creation). -
Switching off the Spring Boot
CloudAutoConfiguration
is easy, but if you do that, you have to remember to switch off the buildpack auto-reconfiguration as well if you don’t want it. The only way to do that is to define a bean definition (can be of typeCloud
orCloudFactory
for instance). -
Spring Boot binds
application.properties
(and other sources of external properties) to@ConfigurationProperties
beans, including but not limited to the ones that it autoconfigures. You can use this feature to tweak pool properties and other settings that need to be different in production environments.
General Advice and Conclusion
We have seen quite a few options and autoconfigurations in this short article, and we’ve only really used thee libraries (Spring Boot, Spring Cloud Connectors, and the Cloud Foundry buildpack auto-reconfiguration JAR) and one platform (Cloud Foundry), not counting local deployment. The buildpack features are really only useful for very simple applications because there is no flexibility to tune the connections in production. That said it is a nice thing to be able to do when prototyping. There are only three main approaches if you want to achieve the goal of deploying the same code locally and in the cloud, yet still being able to make necessary tweaks in production:
-
Use Spring Cloud Connectors to explicitly create
DataSource
and other middleware connections and protect those@Beans
with@Profile("cloud")
. The approach always works, but leads to more code than you might need for many applications. -
Use the Spring Boot default autoconfiguration and declare the cloud bindings using
application.properties
(or in YAML). To take full advantage you have to expliccitly switch off the buildpack auto-reconfiguration as well. -
Use Spring Cloud Connectors to discover the credentials, and bind them to the Spring Boot
@ConfigurationProperties
as default values if present.
The three approaches are actually not incompatible, and can be mixed using@ConfigurationProperties
to provide profile-specific overrides of default configuration (e.g. for setting up connection pools in a different way in a production environment). If you have a relatively simple Spring Boot application, the only way to choose between the approaches is probably personal taste. If you have a non-Spring Boot application then the explicit @Bean
approach will win, and it may also win if you plan to deploy your application in more than one cloud platform (e.g. Heroku and Cloud Foundry).
NOTE: This blog has been a journey of discovery (who knew there was so much to learn?). Thanks go to all those who helped with reviews and comments, in particularScott Frederick, who spotted most of the mistakes in the drafts and always had time to look at a new revision.