Re-organize non-config concerns in spring-cloud-context
Fixes gh-110 See gh-104
This commit is contained in:
@@ -358,97 +358,6 @@ behavior, set the bootstrap configuration property
|
||||
`spring.cloud.config.failFast=true` and the client will halt with
|
||||
an Exception.
|
||||
|
||||
=== Environment Changes
|
||||
|
||||
The application will listen for an `EnvironmentChangedEvent` and react
|
||||
to the change in a couple of standard ways (additional
|
||||
`ApplicationListeners` can be added as `@Beans` by the user in the
|
||||
normal way). When an `EnvironmentChangedEvent` is observed it will
|
||||
have a list of key values that have changed, and the application will
|
||||
use those to:
|
||||
|
||||
* Re-bind any `@ConfigurationProperties` beans in the context
|
||||
* Set the logger levels for any properties in `logging.level.*`
|
||||
|
||||
Note that the Config Client does not by default poll for changes in
|
||||
the `Environment`, and generally we would not recommend that approach
|
||||
for detecting changes (although you could set it up with a
|
||||
`@Scheduled` annotation). If you have a scaled-out client application
|
||||
then it is better to broadcast the `EnvironmentChangedEvent` to all
|
||||
the instances instead of having them polling for changes (e.g. using
|
||||
the https://github.com/spring-cloud/spring-cloud-bus[Spring Cloud
|
||||
Bus]).
|
||||
|
||||
The `EnvironmentChangedEvent` covers a large class of refresh use
|
||||
cases, as long as you can actually make a change to the `Environment`
|
||||
and publish the event (those APIs are public and part of core
|
||||
Spring). You can verify the changes are bound to
|
||||
`@ConfigurationProperties` beans by visiting the `/configprops`
|
||||
endpoint (normal Spring Boot Actuator feature). For instance a
|
||||
`DataSource` can have its `maxPoolSize` changed at runtime (the
|
||||
default `DataSource` created by Spring Boot is an
|
||||
`@ConfigurationProperties` bean) and grow capacity
|
||||
dynamically. Re-binding `@ConfigurationProperties` does not cover
|
||||
another large class of use cases, where you need more control over the
|
||||
refresh, and where you need a change to be atomic over the whole
|
||||
`ApplicationContext`. To address those concerns we have
|
||||
`@RefreshScope`.
|
||||
|
||||
=== Refresh Scope
|
||||
|
||||
A Spring `@Bean` that is marked as `@RefreshScope` will get special
|
||||
treatment when there is a configuration change. This addresses the
|
||||
problem of stateful beans that only get their configuration injected
|
||||
when they are initialized. For instance if a `DataSource` has open
|
||||
connections when the database URL is changed via the `Environment`, we
|
||||
probably want the holders of those connections to be able to complete
|
||||
what they are doing. Then the next time someone borrows a connection
|
||||
from the pool he gets one with the new URL.
|
||||
|
||||
Refresh scope beans are lazy proxies that initialize when they are
|
||||
used (i.e. when a method is called), and the scope acts as a cache of
|
||||
initialized values. To force a bean to re-initialize on the next
|
||||
method call you just need to invalidate its cache entry.
|
||||
|
||||
The `RefreshScope` is a bean in the context and it has a public method
|
||||
`refreshAll()` to refresh all beans in the scope by clearing the
|
||||
target cache. There is also a `refresh(String)` method to refresh an
|
||||
individual bean by name. This functionality is exposed in the
|
||||
`/refresh` endpoint (over HTTP or JMX).
|
||||
|
||||
NOTE: `@RefreshScope` works (technically) on an `@Configuration`
|
||||
class, but it might lead to surprising behaviour: e.g. it does *not*
|
||||
mean that all the `@Beans` defined in that class are themselves
|
||||
`@RefreshScope`. Specifically, anything that depends on those beans
|
||||
cannot rely on them being updated when a refresh is initiated, unless
|
||||
it is itself in `@RefreshScope` (in which it will be rebuilt on a
|
||||
refresh and its dependencies re-injected, at which point they will be
|
||||
re-initialized from the refreshed `@Configuration`).
|
||||
|
||||
=== Encryption and Decryption
|
||||
|
||||
The Config Client has an `Environment` pre-processor for decrypting
|
||||
property values locally. It follows the same rules as the Config
|
||||
Server, and has the same external configuration via `encrypt.\*`. Thus
|
||||
you can use encrypted values in the form `{cipher}*` and as long as
|
||||
there is a valid key then they will be decrypted before the main
|
||||
application context gets the `Environment`. To use the encryption
|
||||
features in a client you need to include Spring Security RSA in your
|
||||
classpath (Maven co-ordinates
|
||||
"org.springframework.security:spring-security-rsa") and you also need
|
||||
the full strength JCE extensions in your JVM (google it and download
|
||||
from Oracle).
|
||||
|
||||
=== Endpoints
|
||||
|
||||
For a Spring Boot Actuator application there are some additional management endpoints:
|
||||
|
||||
* POST to `/env` to update the `Environment` and rebind `@ConfigurationProperties` and log levels
|
||||
* `/refresh` for re-loading the boot strap context and refreshing the `@RefreshScope` beans
|
||||
* `/restart` for closing the `ApplicationContext` and restarting it (disabled by default)
|
||||
* `/pause` and `/resume` for calling the `Lifecycle` methods (`stop()` and `start()` on the `ApplicationContext`)
|
||||
|
||||
|
||||
=== Locating Remote Configuration Resources
|
||||
|
||||
The Config Service serves property sources from `/{name}/{env}/{label}`, where the default bindings in the
|
||||
@@ -464,173 +373,6 @@ rolling back to previous versions of configuration; with the default
|
||||
Config Server implementation it can be a git label, branch name or
|
||||
commit id.
|
||||
|
||||
=== The Bootstrap Application Context
|
||||
|
||||
The Config Client operates by creating a "bootstrap" application
|
||||
context, which is a parent context for the main application. Out of
|
||||
the box it is responsible for loading configuration properties from
|
||||
the Config Server, and also decrypting properties in the local
|
||||
external configuration files. The two contexts share an `Environment`
|
||||
which is the source of external properties for any Spring
|
||||
application. Bootstrap properties are added with high precedence, so
|
||||
they cannot be overridden by local configuration.
|
||||
|
||||
The bootstrap context uses a different convention for locating
|
||||
external configuration than the main application context, so instead
|
||||
of `application.yml` (or `.properties`) you use `bootstrap.yml`,
|
||||
keeping the external configuration for bootstrap and main context
|
||||
nicely separate. Example:
|
||||
|
||||
.bootstrap.yml
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: foo
|
||||
cloud:
|
||||
config:
|
||||
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
|
||||
----
|
||||
|
||||
It is a good idea to set the `spring.application.name` (in
|
||||
`bootstrap.yml` or `application.yml`) if your application needs any
|
||||
application-specific configuration from the server.
|
||||
|
||||
You can disable the bootstrap process completely by setting
|
||||
`spring.cloud.bootstrap.enabled=false` (e.g. in System properties).
|
||||
|
||||
=== Application Context Hierarchies
|
||||
|
||||
If you build an application context from `SpringApplication` or
|
||||
`SpringApplicationBuilder`, then the Bootstrap context is added as a
|
||||
parent to that context. It is a feature of Spring that child contexts
|
||||
inherit property sources and profiles from their parent, so the "main"
|
||||
application context will contain additional property sources, compared
|
||||
to building the same context without Spring Cloud Config. The
|
||||
additional property sources are:
|
||||
|
||||
* "bootstrap": an optional `CompositePropertySource` appears with high
|
||||
priority if any `PropertySourceLocators` are found in the Bootstrap
|
||||
context, and they have non-empty properties. An example would be
|
||||
properties from the Spring Cloud Config Server. See
|
||||
link:#customizing-bootstrap-property-sources[below] for instructions
|
||||
on how to customize the contents of this property source.
|
||||
|
||||
* "applicationConfig: [classpath:bootstrap.yml]" (and friends if
|
||||
Spring profiles are active). If you have a `bootstrap.yml` (or
|
||||
properties) then those properties are used to configure the Bootstrap
|
||||
context, and then they get added to the child context when its parent
|
||||
is set. They have lower precedence than the `application.yml` (or
|
||||
properties) and any other property sources that are added to the child
|
||||
as a normal part of the process of creating a Spring Boot
|
||||
application. See link:#customizing-bootstrap-properties[below] for
|
||||
instructions on how to customize the contents of these property
|
||||
sources.
|
||||
|
||||
Because of the ordering rules of property sources the "bootstrap"
|
||||
entries take precedence, but note that these do not contain any data
|
||||
from `bootstrap.yml`, which has very low precedence, but can be used
|
||||
to set defaults.
|
||||
|
||||
You can extend the context hierarchy by simply setting the parent
|
||||
context of any `ApplicationContext` you create, e.g. using its own
|
||||
interface, or with the `SpringApplicationBuilder` convenience methods
|
||||
(`parent()`, `child()` and `sibling()`). The bootstrap context will be
|
||||
the parent of the most senior ancestor that you create yourself.
|
||||
Every context in the hierarchy will have its own "bootstrap" property
|
||||
source (possibly empty) to avoid promoting values inadvertently from
|
||||
parents down to their descendants. Every context in the hierarchy can
|
||||
also (in principle) have a different `spring.application.name` and
|
||||
hence a different remote property source if there is a Config
|
||||
Server. Normal Spring application context behaviour rules apply to
|
||||
property resolution: properties from a child context override those in
|
||||
the parent, by name and also by property source name (if the child has
|
||||
a property source with the same name as the parent, the one from the
|
||||
parent is not included in the child).
|
||||
|
||||
Note that the `SpringApplicationBuilder` allows you to share an
|
||||
`Environment` amongst the whole hierarchy, but that is not the
|
||||
default. Thus, sibling contexts in particular do not need to have the
|
||||
same profiles or property sources, even though they will share common
|
||||
things with their parent.
|
||||
|
||||
[[customizing-bootstrap-properties]]
|
||||
=== Changing the Location of Bootstrap Properties
|
||||
|
||||
The `bootstrap.yml` (or `.properties) location can be specified using
|
||||
`spring.cloud.bootstrap.name` (default "bootstrap") or
|
||||
`spring.cloud.bootstrap.location` (default empty), e.g. in System
|
||||
properties. Those properties behave like the `spring.config.*`
|
||||
variants with the same name, in fact they are used to set up the
|
||||
bootstrap `ApplicationContext` by setting those properties in its
|
||||
`Environment`. If there is an active profile (from
|
||||
`spring.profiles.active` or through the `Environment` API in the
|
||||
context you are building) then properties in that profile will be
|
||||
loaded as well, just like in a regular Spring Boot app, e.g. from
|
||||
`bootstrap-development.properties` for a "development" profile.
|
||||
|
||||
=== Customizing the Bootstrap Configuration
|
||||
|
||||
The bootstrap context can be trained to do anything you like by adding
|
||||
entries to `/META-INF/spring.factories` under the key
|
||||
`org.springframework.cloud.bootstrap.BootstrapConfiguration`. This is
|
||||
a comma-separated list of Spring `@Configuration` classes which will
|
||||
be used to create the context. Any beans that you want to be available
|
||||
to the main application context for autowiring can be created here,
|
||||
and also there is a special contract for `@Beans` of type
|
||||
`ApplicationContextInitializer`.
|
||||
|
||||
The bootstrap process ends by injecting initializers into the main
|
||||
`SpringApplication` instance (i.e. the normal Spring Boot startup
|
||||
sequence, whether it is running as a standalone app or deployed in an
|
||||
application server). First a bootstrap context is created from the
|
||||
classes found in `spring.factories` and then all `@Beans` of type
|
||||
`ApplicationContextInitializer` are added to the main
|
||||
`SpringApplication` before it is started.
|
||||
|
||||
[[customizing-bootstrap-property-sources]]
|
||||
=== Customizing the Bootstrap Property Sources
|
||||
|
||||
The default property source for external configuration added by the
|
||||
bootstrap process is the Config Server, but you can add additional
|
||||
sources by adding beans of type `PropertySourceLocator` to the
|
||||
bootstrap context (via `spring.factories`). You could use this to
|
||||
insert additional properties from a different server, or from a
|
||||
database, for instance.
|
||||
|
||||
As an example, consider the following trivial custom locator:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Configuration
|
||||
public class CustomPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
@Override
|
||||
public PropertySource<?> locate(Environment environment) {
|
||||
return new MapPropertySource("customProperty",
|
||||
Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
The `Environment` that is passed in is the one for the
|
||||
`ApplicationContext` about to be created, i.e. the one that we are
|
||||
supplying additional property sources for. It will already have its
|
||||
normal Spring Boot-provided property sources, so you can use those to
|
||||
locate a property source specific to this `Environment` (e.g. by
|
||||
keying it on the `spring.application.name`, as is done in the default
|
||||
Config Server property source locator).
|
||||
|
||||
If you create a jar with this class in it and then add a
|
||||
`META-INF/spring.factories` containing:
|
||||
|
||||
----
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator
|
||||
----
|
||||
|
||||
then the "customProperty" `PropertySource` will show up in any
|
||||
application that includes that jar on its classpath.
|
||||
|
||||
=== Security
|
||||
|
||||
If you use HTTP Basic security on the server then clients just need to
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user