Commit 14c1b093 authored by Phillip Webb's avatar Phillip Webb

Polish

parent da692868
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.redis;
import java.util.Properties;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.data.redis.connection.ClusterInfo;
/**
* Shared class used by {@link RedisHealthIndicator} and
* {@link RedisReactiveHealthIndicator} to provide health details.
*
* @author Phillip Webb
*/
class RedisHealth {
static Builder up(Health.Builder builder, Properties info) {
builder.withDetail("version", info.getProperty("redis_version"));
return builder.up();
}
static Builder up(Health.Builder builder, ClusterInfo clusterInfo) {
builder.withDetail("cluster_size", clusterInfo.getClusterSize());
builder.withDetail("slots_up", clusterInfo.getSlotsOk());
builder.withDetail("slots_fail", clusterInfo.getSlotsFail());
return builder.up();
}
}
......@@ -19,7 +19,6 @@ package org.springframework.boot.actuate.redis;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.data.redis.connection.ClusterInfo;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
......@@ -37,8 +36,6 @@ import org.springframework.util.Assert;
*/
public class RedisHealthIndicator extends AbstractHealthIndicator {
private static final String REDIS_VERSION_PROPERTY = "redis_version";
private final RedisConnectionFactory redisConnectionFactory;
public RedisHealthIndicator(RedisConnectionFactory connectionFactory) {
......@@ -60,14 +57,10 @@ public class RedisHealthIndicator extends AbstractHealthIndicator {
private void doHealthCheck(Health.Builder builder, RedisConnection connection) {
if (connection instanceof RedisClusterConnection) {
ClusterInfo clusterInfo = ((RedisClusterConnection) connection).clusterGetClusterInfo();
builder.up().withDetail("cluster_size", clusterInfo.getClusterSize())
.withDetail("slots_up", clusterInfo.getSlotsOk())
.withDetail("slots_fail", clusterInfo.getSlotsFail());
RedisHealth.up(builder, ((RedisClusterConnection) connection).clusterGetClusterInfo());
}
else {
String version = connection.info().getProperty(REDIS_VERSION_PROPERTY);
builder.up().withDetail("version", version);
RedisHealth.up(builder, connection.info());
}
}
......
......@@ -40,8 +40,6 @@ import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
*/
public class RedisReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
private static final String REDIS_VERSION_PROPERTY = "redis_version";
private final ReactiveRedisConnectionFactory connectionFactory;
public RedisReactiveHealthIndicator(ReactiveRedisConnectionFactory connectionFactory) {
......@@ -54,35 +52,30 @@ public class RedisReactiveHealthIndicator extends AbstractReactiveHealthIndicato
return getConnection().flatMap((connection) -> doHealthCheck(builder, connection));
}
private Mono<Health> doHealthCheck(Health.Builder builder, ReactiveRedisConnection connection) {
if (connection instanceof ReactiveRedisClusterConnection) {
ReactiveRedisClusterConnection clusterConnection = (ReactiveRedisClusterConnection) connection;
return clusterConnection.clusterGetClusterInfo().map((info) -> up(builder, info))
.onErrorResume((ex) -> Mono.just(down(builder, ex)))
.flatMap((health) -> clusterConnection.closeLater().thenReturn(health));
private Mono<ReactiveRedisConnection> getConnection() {
return Mono.fromSupplier(this.connectionFactory::getReactiveConnection)
.subscribeOn(Schedulers.boundedElastic());
}
return connection.serverCommands().info().map((info) -> up(builder, info))
.onErrorResume((ex) -> Mono.just(down(builder, ex)))
private Mono<Health> doHealthCheck(Health.Builder builder, ReactiveRedisConnection connection) {
return getHealth(builder, connection).onErrorResume((ex) -> Mono.just(builder.down(ex).build()))
.flatMap((health) -> connection.closeLater().thenReturn(health));
}
private Mono<ReactiveRedisConnection> getConnection() {
return Mono.fromSupplier(this.connectionFactory::getReactiveConnection)
.subscribeOn(Schedulers.boundedElastic());
private Mono<Health> getHealth(Health.Builder builder, ReactiveRedisConnection connection) {
if (connection instanceof ReactiveRedisClusterConnection) {
return ((ReactiveRedisClusterConnection) connection).clusterGetClusterInfo()
.map((info) -> up(builder, info));
}
return connection.serverCommands().info().map((info) -> up(builder, info));
}
private Health up(Health.Builder builder, Properties info) {
return builder.up().withDetail("version", info.getProperty(REDIS_VERSION_PROPERTY)).build();
return RedisHealth.up(builder, info).build();
}
private Health up(Health.Builder builder, ClusterInfo clusterInfo) {
return builder.up().withDetail("cluster_size", clusterInfo.getClusterSize())
.withDetail("slots_up", clusterInfo.getSlotsOk()).withDetail("slots_fail", clusterInfo.getSlotsFail())
.build();
}
private Health down(Health.Builder builder, Throwable cause) {
return builder.down(cause).build();
return RedisHealth.up(builder, clusterInfo).build();
}
}
......@@ -243,11 +243,11 @@ public class WebMvcProperties {
throw new IncompatibleConfigurationException("spring.mvc.pathmatch.matching-strategy",
"spring.mvc.pathmatch.use-suffix-pattern");
}
else if (this.getPathmatch().isUseRegisteredSuffixPattern()) {
if (this.getPathmatch().isUseRegisteredSuffixPattern()) {
throw new IncompatibleConfigurationException("spring.mvc.pathmatch.matching-strategy",
"spring.mvc.pathmatch.use-registered-suffix-pattern");
}
else if (!this.getServlet().getServletMapping().equals("/")) {
if (!this.getServlet().getServletMapping().equals("/")) {
throw new IncompatibleConfigurationException("spring.mvc.pathmatch.matching-strategy",
"spring.mvc.servlet.path");
}
......
......@@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.ApplicationContextFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
......@@ -111,7 +112,7 @@ public class SpringBootContextLoader extends AbstractContextLoader {
application.setWebApplicationType(WebApplicationType.REACTIVE);
if (!isEmbeddedWebEnvironment(config)) {
application.setApplicationContextFactory(
(webApplicationType) -> new GenericReactiveWebApplicationContext());
ApplicationContextFactory.of(GenericReactiveWebApplicationContext::new));
}
}
else {
......
......@@ -16,8 +16,13 @@
package org.springframework.boot;
import java.util.function.Supplier;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Strategy interface for creating the {@link ConfigurableApplicationContext} used by a
......@@ -26,11 +31,33 @@ import org.springframework.context.ConfigurableApplicationContext;
* context.
*
* @author Andy Wilkinson
* @author Phillip Webb
* @since 2.4.0
*/
@FunctionalInterface
public interface ApplicationContextFactory {
/**
* A default {@link ApplicationContextFactory} implementation that will create an
* appropriate context for the {@link WebApplicationType}.
*/
static ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
/**
* Creates the {@link ConfigurableApplicationContext application context} for a
* {@link SpringApplication}, respecting the given {@code webApplicationType}.
......@@ -46,8 +73,19 @@ public interface ApplicationContextFactory {
* @return the factory that will instantiate the context class
* @see BeanUtils#instantiateClass(Class)
*/
static ApplicationContextFactory forContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {
return (webApplicationType) -> BeanUtils.instantiateClass(contextClass);
static ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {
return of(() -> BeanUtils.instantiateClass(contextClass));
}
/**
* Creates an {@code ApplicationContextFactory} that will create contexts by calling
* the given {@link Supplier}.
* @param supplier the context supplier, for example
* {@code AnnotationConfigApplicationContext::new}
* @return the factory that will instantiate the context class
*/
static ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {
return (webApplicationType) -> supplier.get();
}
}
......@@ -245,7 +245,7 @@ public class SpringApplication {
private boolean lazyInitialization = false;
private ApplicationContextFactory applicationContextFactory = new DefaultApplicationContextFactory();
private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;
/**
* Create a new {@link SpringApplication} instance. The application context will load
......@@ -1150,7 +1150,7 @@ public class SpringApplication {
@Deprecated
public void setApplicationContextClass(Class<? extends ConfigurableApplicationContext> applicationContextClass) {
this.webApplicationType = WebApplicationType.deduceFromApplicationContext(applicationContextClass);
this.applicationContextFactory = ApplicationContextFactory.forContextClass(applicationContextClass);
this.applicationContextFactory = ApplicationContextFactory.ofContextClass(applicationContextClass);
}
/**
......@@ -1164,7 +1164,8 @@ public class SpringApplication {
* @since 2.4.0
*/
public void setApplicationContextFactory(ApplicationContextFactory applicationContextFactory) {
this.applicationContextFactory = applicationContextFactory;
this.applicationContextFactory = (applicationContextFactory != null) ? applicationContextFactory
: ApplicationContextFactory.DEFAULT;
}
/**
......@@ -1309,26 +1310,4 @@ public class SpringApplication {
return new LinkedHashSet<>(list);
}
private static final class DefaultApplicationContextFactory implements ApplicationContextFactory {
@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
try {
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
}
catch (Exception ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextFactory", ex);
}
}
}
}
......@@ -42,8 +42,8 @@ class SpringApplicationNoWebTests {
@Test
void specificApplicationContextClass() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setApplicationContextFactory(
ApplicationContextFactory.forContextClass(StaticApplicationContext.class));
application
.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class));
ConfigurableApplicationContext context = application.run();
assertThat(context).isInstanceOf(StaticApplicationContext.class);
context.close();
......
......@@ -331,8 +331,8 @@ class SpringApplicationTests {
@Test
void specificApplicationContextFactory() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setApplicationContextFactory(
ApplicationContextFactory.forContextClass(StaticApplicationContext.class));
application
.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class));
this.context = application.run();
assertThat(this.context).isInstanceOf(StaticApplicationContext.class);
}
......@@ -889,8 +889,7 @@ class SpringApplicationTests {
@Test
void registerShutdownHook() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application
.setApplicationContextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
application.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
this.context = application.run();
SpyApplicationContext applicationContext = (SpyApplicationContext) this.context;
verify(applicationContext.getApplicationContext()).registerShutdownHook();
......@@ -899,8 +898,7 @@ class SpringApplicationTests {
@Test
void registerListener() {
SpringApplication application = new SpringApplication(ExampleConfig.class, ListenerConfig.class);
application
.setApplicationContextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
application.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
Set<ApplicationEvent> events = new LinkedHashSet<>();
application.addListeners((ApplicationListener<ApplicationEvent>) events::add);
this.context = application.run();
......@@ -913,8 +911,7 @@ class SpringApplicationTests {
void registerListenerWithCustomMulticaster() {
SpringApplication application = new SpringApplication(ExampleConfig.class, ListenerConfig.class,
Multicaster.class);
application
.setApplicationContextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
application.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
Set<ApplicationEvent> events = new LinkedHashSet<>();
application.addListeners((ApplicationListener<ApplicationEvent>) events::add);
this.context = application.run();
......@@ -994,8 +991,7 @@ class SpringApplicationTests {
@Test
void registerShutdownHookOff() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application
.setApplicationContextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
application.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
application.setRegisterShutdownHook(false);
this.context = application.run();
SpyApplicationContext applicationContext = (SpyApplicationContext) this.context;
......
......@@ -69,7 +69,7 @@ class SpringApplicationBuilderTests {
@Test
void profileAndProperties() {
SpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(StaticApplicationContext.class))
.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))
.profiles("foo").properties("foo=bar");
this.context = application.run();
assertThat(this.context).isInstanceOf(StaticApplicationContext.class);
......@@ -80,7 +80,7 @@ class SpringApplicationBuilderTests {
@Test
void propertiesAsMap() {
SpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(StaticApplicationContext.class))
.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))
.properties(Collections.singletonMap("bar", "foo"));
this.context = application.run();
assertThat(this.context.getEnvironment().getProperty("bar")).isEqualTo("foo");
......@@ -89,7 +89,7 @@ class SpringApplicationBuilderTests {
@Test
void propertiesAsProperties() {
SpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(StaticApplicationContext.class))
.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))
.properties(StringUtils.splitArrayElementsIntoProperties(new String[] { "bar=foo" }, "="));
this.context = application.run();
assertThat(this.context.getEnvironment().getProperty("bar")).isEqualTo("foo");
......@@ -98,7 +98,7 @@ class SpringApplicationBuilderTests {
@Test
void propertiesWithRepeatSeparator() {
SpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(StaticApplicationContext.class))
.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))
.properties("one=c:\\logging.file.name", "two=a:b", "three:c:\\logging.file.name", "four:a:b");
this.context = application.run();
ConfigurableEnvironment environment = this.context.getEnvironment();
......@@ -120,7 +120,7 @@ class SpringApplicationBuilderTests {
@Test
void specificApplicationContextFactory() {
SpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(StaticApplicationContext.class));
.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class));
this.context = application.run();
assertThat(this.context).isInstanceOf(StaticApplicationContext.class);
}
......@@ -128,7 +128,7 @@ class SpringApplicationBuilderTests {
@Test
void parentContextCreationThatIsRunDirectly() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
application.parent(ExampleConfig.class);
this.context = application.run("foo.bar=baz");
verify(((SpyApplicationContext) this.context).getApplicationContext()).setParent(any(ApplicationContext.class));
......@@ -141,7 +141,7 @@ class SpringApplicationBuilderTests {
@Test
void parentContextCreationThatIsBuiltThenRun() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
application.parent(ExampleConfig.class);
this.context = application.build("a=alpha").run("b=bravo");
verify(((SpyApplicationContext) this.context).getApplicationContext()).setParent(any(ApplicationContext.class));
......@@ -153,7 +153,7 @@ class SpringApplicationBuilderTests {
@Test
void parentContextCreationWithChildShutdown() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class))
.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class))
.registerShutdownHook(true);
application.parent(ExampleConfig.class);
this.context = application.run();
......@@ -164,7 +164,7 @@ class SpringApplicationBuilderTests {
@Test
void contextWithClassLoader() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
ClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
application.resourceLoader(new DefaultResourceLoader(classLoader));
this.context = application.run();
......@@ -174,7 +174,7 @@ class SpringApplicationBuilderTests {
@Test
void parentContextWithClassLoader() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)
.contextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
ClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
application.resourceLoader(new DefaultResourceLoader(classLoader));
application.parent(ExampleConfig.class);
......@@ -186,7 +186,7 @@ class SpringApplicationBuilderTests {
void parentFirstCreation() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)
.child(ChildConfig.class);
application.contextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
application.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
this.context = application.run();
verify(((SpyApplicationContext) this.context).getApplicationContext()).setParent(any(ApplicationContext.class));
assertThat(((SpyApplicationContext) this.context).getRegisteredShutdownHook()).isFalse();
......@@ -243,7 +243,7 @@ class SpringApplicationBuilderTests {
void parentContextIdentical() {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class);
application.parent(ExampleConfig.class);
application.contextFactory(ApplicationContextFactory.forContextClass(SpyApplicationContext.class));
application.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));
this.context = application.run();
verify(((SpyApplicationContext) this.context).getApplicationContext()).setParent(any(ApplicationContext.class));
}
......
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