When the RefreshEndpoint makes a new Environment it creates a new
ApplicationContext with (hopefully) empty sources. If the user has
set spring.main.sources it won't be empty, so we should take care
to mask it off in the process.
Fixes gh-79
Repots DOWN if there are errors in RefreshScope or
ConfigurationProperties rebinding, N.B. RefreshScope instantiates
its beans lazily after a refresh by default, so you won't see an
error until the bean is used.
Fixes gh-85
The fact that PropertySourceBootstrapConfiguration was re-using the
"bootstrap" property source name from the listener was a problem. The
listener has to be able to manage its own temporary property source name.
Fixes gh-83
The bootstrap.properties need to stick with the default properties
during the process of initializing the application.properties
otherwise the ordering ends up wrong because of the addLast()
semantics in an Environment merge. To do this is a bit ugly with
the additional constraint that the default properties has to
remain a MapPropertySource (so that other processors can append
to it if needed). So we created a custom extension of
MapPropertySource that also carries all the bootstrap properties
during the phase where the application.properties are being
processed, but unpacks them as soon as possible afterwards
in an ApplicationContextInitializer, preserving the order, but
making the bootstrap.properties available effectively for the
whole of the startup and initializaion phase of the main context.
The biggest problem addressed here is one where an
EnvironmentPostProcessor (reasonably) adds entries to the
defaultProperties in the bootstrap context, but then that
property source is not merged with the parent, or is merged
too late (because it only happens when the application context
parent is set). The result would be that things that were activated
during bootstrap would be not be activated in the main context, or
would be activated too late (early enough for beans to bind to but
not for other listeners and post processors to get access to the
additional properties).
See https://github.com/spring-cloud/spring-cloud-sleuth/issues/126
We only need one special name for a property source. In the end it
gets used twice, but this simplifies the logic a bit and ensures that
there is never a PropertySource with that name and things like
spring.application.name=bootstrap in it.
If user has @EnableDiscoveryClient but no implementation (e.g. if he
just has @EnableZuulProxy) the autoconfig will now kick in and
provide an instance of NoopDiscoveryClient.
Fixes gh-80
This commit introduces support to easily discover resources in remote
service APIs and periodically validating they're still available.
The core concept is a RemoteResource and its primary implementation
DiscoveredResource which consists of a ServiceInstanceProvider and a
TraversalDescription. The service instance provider abstracts the location
of the service the DiscoveredResource is hosted at. Currently there are
two implementations available: a StaticServiceInstanceProvider that — as
the name suggests — returns a statically configured instance, as well as
the DynamicServiceInstanceProvider which takes a DiscoveryClient and service
name as input to dynamically discover the ServiceInstance on request.
The TraversalDefinition is a SAM type that allows to define the path traversals
that shall be executed to discover the target resource within the service
instance. This allows the following configuration:
DiscoveryClient client = …
ServiceInstanceProvider provider = new DynamicServiceInstanceProvider(client, "stores");
RemoteResource resource = new DiscoveredResource(provider, traverson -> traverson.follow("stores", "search", "by-location");
This will cause the following to happen:
1. In this default state the resource is undiscovered and calls to getLink()
will return null.
2. A call to verifyOrDiscover() will trigger resource discovery, i.e. lookup
the service instance using the discovery client, execute the path traversal
as defined and store the final link discovered ("by-location") in the
discovered resource.
3. Calls to getLink() will return that link. Calls to verifyOrDiscover()
will issue a HEAD request to verify the resource is still available and
reset the link if not. Subsequent calls to verifyOrDiscover() will trigger
rediscovery.
That means that we basically shield against either the service instance becoming
unavailable or the resource becoming unavailable within the service instance
(due to some URI restructuring or the like).
The calls to verifyOrDiscover() are currently automated by a RemoteResourceRefresher
which is auto-configured if a RemoteResource is declared as Spring bean
and its initial and fixed delay can be configured via properties in the
spring.cloud.hypermedia namespace.
This ensures that any fetaures that require a bean to be instantiated
(for instance @Scheduled) behave the same for @RefreshScope and normal
singletons.
Fixes gh-74
That'll show me for trying to code right before the holidays.
Not only was the auto-config in the WRONG package, I forgot to enable it in autoconfiguration!
fixes gh-bonehead
Otherwise multiple instances of a scoped target can be created
if several threads need one at the same time. This isn't always
going to be a problem, but it breaks the singleton semantics, and
might lead to surprising results and/or performance issues if bean
creation is expensive.
It's kind of a corner case, but not a very small corner: if a /refresh
leads to a change in a key that was overridden from its default value (e.g.
n a profile-specific config file) then the key is not identified as changed.
The change is still applied.
This commit fixes the key computation and adds a couple of tests.
Fixes gh-73