Polish Actuator MVC customization support
See gh-3345
This commit is contained in:
@@ -17,9 +17,6 @@
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
@@ -36,7 +33,6 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.boot.actuate.condition.ConditionalOnManagementMvcContext;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
@@ -82,7 +78,8 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||
@AutoConfigureAfter({ PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedServletContainerAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ManagementServerPropertiesAutoConfiguration.class })
|
||||
public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, SmartInitializingSingleton {
|
||||
public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
SmartInitializingSingleton {
|
||||
|
||||
private static Log logger = LogFactory.getLog(EndpointWebMvcAutoConfiguration.class);
|
||||
|
||||
@@ -123,38 +120,19 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
}
|
||||
|
||||
private void createChildManagementContext() {
|
||||
|
||||
final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||
childContext.setParent(this.applicationContext);
|
||||
childContext.setNamespace("management");
|
||||
childContext.setId(this.applicationContext.getId() + ":management");
|
||||
|
||||
List<Class<?>> configurations = new ArrayList<Class<?>>();
|
||||
configurations.addAll(Arrays.<Class<?>> asList(
|
||||
EndpointWebMvcChildContextConfiguration.class,
|
||||
childContext.register(EndpointWebMvcChildContextConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedServletContainerAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class));
|
||||
// Register the ManagementServerChildContextConfiguration first followed
|
||||
// by various specific AutoConfiguration classes. NOTE: The child context
|
||||
// is intentionally not completely auto-configured.
|
||||
childContext.register(configurations.toArray(new Class<?>[0]));
|
||||
|
||||
// Ensure close on the parent also closes the child
|
||||
if (this.applicationContext instanceof ConfigurableApplicationContext) {
|
||||
((ConfigurableApplicationContext) this.applicationContext)
|
||||
.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
if (event.getApplicationContext() == EndpointWebMvcAutoConfiguration.this.applicationContext) {
|
||||
childContext.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
managementContextResolver().setApplicationContext(childContext);
|
||||
DispatcherServletAutoConfiguration.class);
|
||||
CloseEventPropagationListener
|
||||
.addIfPossible(this.applicationContext, childContext);
|
||||
try {
|
||||
childContext.refresh();
|
||||
managementContextResolver().setApplicationContext(childContext);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
// No support currently for deploying a war with management.port=<different>,
|
||||
@@ -231,6 +209,45 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ApplicationListener} to propagate the {@link ContextClosedEvent} from a
|
||||
* parent to a child.
|
||||
*/
|
||||
private static class CloseEventPropagationListener implements
|
||||
ApplicationListener<ContextClosedEvent> {
|
||||
|
||||
private final ApplicationContext parentContext;
|
||||
|
||||
private final ConfigurableApplicationContext childContext;
|
||||
|
||||
public CloseEventPropagationListener(ApplicationContext parentContext,
|
||||
ConfigurableApplicationContext childContext) {
|
||||
this.parentContext = parentContext;
|
||||
this.childContext = childContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
if (event.getApplicationContext() == this.parentContext) {
|
||||
this.childContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addIfPossible(ApplicationContext parentContext,
|
||||
ConfigurableApplicationContext childContext) {
|
||||
if (parentContext instanceof ConfigurableApplicationContext) {
|
||||
add((ConfigurableApplicationContext) parentContext, childContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static void add(ConfigurableApplicationContext parentContext,
|
||||
ConfigurableApplicationContext childContext) {
|
||||
parentContext.addApplicationListener(new CloseEventPropagationListener(
|
||||
parentContext, childContext));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static enum ManagementServerPort {
|
||||
|
||||
DISABLE, SAME, DIFFERENT;
|
||||
@@ -267,31 +284,4 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
|
||||
}
|
||||
|
||||
public static class ManagementContextResolver {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public ManagementContextResolver(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public MvcEndpoints getMvcEndpoints() {
|
||||
try {
|
||||
return applicationContext.getBean(MvcEndpoints.class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
* @see EndpointWebMvcAutoConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@Import(EndpointWebMvcImportSelector.class)
|
||||
public class EndpointWebMvcChildContextConfiguration {
|
||||
|
||||
private static Log logger = LogFactory
|
||||
@@ -83,14 +85,119 @@ public class EndpointWebMvcChildContextConfiguration {
|
||||
@Autowired
|
||||
private ManagementServerProperties managementServerProperties;
|
||||
|
||||
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
|
||||
public DispatcherServlet dispatcherServlet() {
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet();
|
||||
// Ensure the parent configuration does not leak down to us
|
||||
dispatcherServlet.setDetectAllHandlerAdapters(false);
|
||||
dispatcherServlet.setDetectAllHandlerExceptionResolvers(false);
|
||||
dispatcherServlet.setDetectAllHandlerMappings(false);
|
||||
dispatcherServlet.setDetectAllViewResolvers(false);
|
||||
return dispatcherServlet;
|
||||
}
|
||||
|
||||
@Bean(name = DispatcherServlet.HANDLER_MAPPING_BEAN_NAME)
|
||||
public CompositeHandlerMapping compositeHandlerMapping() {
|
||||
return new CompositeHandlerMapping();
|
||||
}
|
||||
|
||||
@Bean(name = DispatcherServlet.HANDLER_ADAPTER_BEAN_NAME)
|
||||
public CompositeHandlerAdapter compositeHandlerAdapter() {
|
||||
return new CompositeHandlerAdapter();
|
||||
}
|
||||
|
||||
@Bean(name = DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)
|
||||
public CompositeHandlerExceptionResolver compositeHandlerExceptionResolver() {
|
||||
return new CompositeHandlerExceptionResolver();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServerCustomization serverCustomization() {
|
||||
return new ServerCustomization();
|
||||
}
|
||||
|
||||
/*
|
||||
* The error controller is present but not mapped as an endpoint in this context
|
||||
* because of the DispatcherServlet having had it's HandlerMapping explicitly
|
||||
* disabled. So we expose the same feature but only for machine endpoints.
|
||||
*/
|
||||
@Bean
|
||||
public ManagementErrorEndpoint errorEndpoint(final ErrorAttributes errorAttributes) {
|
||||
return new ManagementErrorEndpoint(this.errorPath, errorAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration to add {@link HandlerMapping} for {@link MvcEndpoint}s. See
|
||||
* {@link SecureEndpointHandlerMappingConfiguration} for an extended version that also
|
||||
* configures the security filter.
|
||||
*/
|
||||
@Configuration
|
||||
@Import(EndpointWebMvcImportSelector.class)
|
||||
protected static class EndpointWebMvcConfiguration {
|
||||
@ConditionalOnMissingClass("org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter")
|
||||
protected static class EndpointHandlerMappingConfiguration {
|
||||
|
||||
@Autowired
|
||||
public void handlerMapping(MvcEndpoints endpoints,
|
||||
ListableBeanFactory beanFactory, EndpointHandlerMapping mapping) {
|
||||
// In a child context we definitely want to see the parent endpoints
|
||||
mapping.setDetectHandlerMethodsInAncestorContexts(true);
|
||||
postProcessMapping(beanFactory, mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow additional post processing of {@link EndpointHandlerMapping}.
|
||||
* @param beanFactory the source bean factory
|
||||
* @param mapping the mapping to customize
|
||||
*/
|
||||
protected void postProcessMapping(ListableBeanFactory beanFactory,
|
||||
EndpointHandlerMapping mapping) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of {@link EndpointHandlerMappingConfiguration} that also configures the
|
||||
* security filter.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
|
||||
protected static class SecureEndpointHandlerMappingConfiguration extends
|
||||
EndpointHandlerMappingConfiguration {
|
||||
|
||||
@Override
|
||||
protected void postProcessMapping(ListableBeanFactory beanFactory,
|
||||
EndpointHandlerMapping mapping) {
|
||||
// The parent context has the security filter, so we need to get it injected
|
||||
// with our EndpointHandlerMapping if we can.
|
||||
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
|
||||
ManagementWebSecurityConfigurerAdapter.class).length == 1) {
|
||||
ManagementWebSecurityConfigurerAdapter bean = beanFactory
|
||||
.getBean(ManagementWebSecurityConfigurerAdapter.class);
|
||||
bean.setEndpointHandlerMapping(mapping);
|
||||
}
|
||||
else {
|
||||
logger.warn("No single bean of type "
|
||||
+ ManagementWebSecurityConfigurerAdapter.class.getSimpleName()
|
||||
+ " found (this might make some endpoints inaccessible without authentication)");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class ServerCustomization implements
|
||||
EmbeddedServletContainerCustomizer, Ordered {
|
||||
@ConditionalOnClass({ EnableWebSecurity.class, Filter.class })
|
||||
@ConditionalOnBean(name = "springSecurityFilterChain", search = SearchStrategy.PARENTS)
|
||||
public static class EndpointWebMvcChildContextSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public Filter springSecurityFilterChain(HierarchicalBeanFactory beanFactory) {
|
||||
BeanFactory parent = beanFactory.getParentBeanFactory();
|
||||
return parent.getBean("springSecurityFilterChain", Filter.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ServerCustomization implements EmbeddedServletContainerCustomizer,
|
||||
Ordered {
|
||||
|
||||
@Value("${error.path:/error}")
|
||||
private String errorPath = "/error";
|
||||
@@ -131,22 +238,7 @@ public class EndpointWebMvcChildContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
|
||||
public DispatcherServlet dispatcherServlet() {
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet();
|
||||
|
||||
// Ensure the parent configuration does not leak down to us
|
||||
dispatcherServlet.setDetectAllHandlerAdapters(false);
|
||||
dispatcherServlet.setDetectAllHandlerExceptionResolvers(false);
|
||||
dispatcherServlet.setDetectAllHandlerMappings(false);
|
||||
dispatcherServlet.setDetectAllViewResolvers(false);
|
||||
|
||||
return dispatcherServlet;
|
||||
}
|
||||
|
||||
@Configuration(DispatcherServlet.HANDLER_MAPPING_BEAN_NAME)
|
||||
@EnableWebMvc
|
||||
public static class CompositeHandlerMapping implements HandlerMapping {
|
||||
static class CompositeHandlerMapping implements HandlerMapping {
|
||||
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
@@ -178,8 +270,7 @@ public class EndpointWebMvcChildContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(DispatcherServlet.HANDLER_ADAPTER_BEAN_NAME)
|
||||
public static class CompositeHandlerAdapter implements HandlerAdapter {
|
||||
static class CompositeHandlerAdapter implements HandlerAdapter {
|
||||
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
@@ -236,9 +327,7 @@ public class EndpointWebMvcChildContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)
|
||||
public static class CompositeHandlerExceptionResolver implements
|
||||
HandlerExceptionResolver {
|
||||
static class CompositeHandlerExceptionResolver implements HandlerExceptionResolver {
|
||||
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
@@ -272,84 +361,4 @@ public class EndpointWebMvcChildContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The error controller is present but not mapped as an endpoint in this context
|
||||
* because of the DispatcherServlet having had it's HandlerMapping explicitly
|
||||
* disabled. So we expose the same feature but only for machine endpoints.
|
||||
*/
|
||||
@Bean
|
||||
public ManagementErrorEndpoint errorEndpoint(final ErrorAttributes errorAttributes) {
|
||||
return new ManagementErrorEndpoint(this.errorPath, errorAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration to add {@link HandlerMapping} for {@link MvcEndpoint}s. See
|
||||
* {@link SecureEndpointHandlerMappingConfiguration} for an extended version that also
|
||||
* configures the security filter.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingClass("org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter")
|
||||
protected static class EndpointHandlerMappingConfiguration {
|
||||
|
||||
@Autowired
|
||||
public void handlerMapping(MvcEndpoints endpoints,
|
||||
ListableBeanFactory beanFactory, EndpointHandlerMapping mapping) {
|
||||
// In a child context we definitely want to see the parent endpoints
|
||||
mapping.setDetectHandlerMethodsInAncestorContexts(true);
|
||||
postProcessMapping(beanFactory, mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow additional post processing of {@link EndpointHandlerMapping}.
|
||||
* @param beanFactory the source bean factory
|
||||
* @param mapping the mapping to customize
|
||||
*/
|
||||
protected void postProcessMapping(ListableBeanFactory beanFactory,
|
||||
EndpointHandlerMapping mapping) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of {@link EndpointHandlerMappingConfiguration} that also configures the
|
||||
* security filter.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
|
||||
protected static class SecureEndpointHandlerMappingConfiguration extends
|
||||
EndpointHandlerMappingConfiguration {
|
||||
|
||||
@Override
|
||||
protected void postProcessMapping(ListableBeanFactory beanFactory,
|
||||
EndpointHandlerMapping mapping) {
|
||||
// The parent context has the security filter, so we need to get it injected
|
||||
// with our EndpointHandlerMapping if we can.
|
||||
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
|
||||
ManagementWebSecurityConfigurerAdapter.class).length == 1) {
|
||||
ManagementWebSecurityConfigurerAdapter bean = beanFactory
|
||||
.getBean(ManagementWebSecurityConfigurerAdapter.class);
|
||||
bean.setEndpointHandlerMapping(mapping);
|
||||
}
|
||||
else {
|
||||
logger.warn("No single bean of type "
|
||||
+ ManagementWebSecurityConfigurerAdapter.class.getSimpleName()
|
||||
+ " found (this might make some endpoints inaccessible without authentication)");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ EnableWebSecurity.class, Filter.class })
|
||||
@ConditionalOnBean(name = "springSecurityFilterChain", search = SearchStrategy.PARENTS)
|
||||
public static class EndpointWebMvcChildContextSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public Filter springSecurityFilterChain(HierarchicalBeanFactory beanFactory) {
|
||||
BeanFactory parent = beanFactory.getParentBeanFactory();
|
||||
return parent.getBean("springSecurityFilterChain", Filter.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -22,6 +22,7 @@ import java.util.Set;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties.Security;
|
||||
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
@@ -45,12 +46,14 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Configuration to expose {@link Endpoint} instances over Spring MVC.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({ HealthMvcEndpointProperties.class,
|
||||
EndpointCorsProperties.class })
|
||||
EndpointCorsProperties.class })
|
||||
public class EndpointWebMvcConfiguration {
|
||||
|
||||
@Autowired
|
||||
@@ -75,7 +78,8 @@ public class EndpointWebMvcConfiguration {
|
||||
CorsConfiguration corsConfiguration = getCorsConfiguration(this.corsProperties);
|
||||
EndpointHandlerMapping mapping = new EndpointHandlerMapping(endpoints,
|
||||
corsConfiguration);
|
||||
boolean disabled = this.managementServerProperties.getPort()!=null && this.managementServerProperties.getPort()==-1;
|
||||
boolean disabled = this.managementServerProperties.getPort() != null
|
||||
&& this.managementServerProperties.getPort() == -1;
|
||||
mapping.setDisabled(disabled);
|
||||
if (!disabled) {
|
||||
mapping.setPrefix(this.managementServerProperties.getContextPath());
|
||||
|
||||
@@ -29,27 +29,26 @@ import org.springframework.core.type.AnnotationMetadata;
|
||||
* Selects configuration classes for the Actuator MVC endpoints. Customize the MVC
|
||||
* endpoints by adding an entries to <code>/META-INF/spring.factories</code> under the
|
||||
* {@link EndpointWebMvcConfiguration} key.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class EndpointWebMvcImportSelector implements DeferredImportSelector,
|
||||
class EndpointWebMvcImportSelector implements DeferredImportSelector,
|
||||
BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
private ClassLoader classLoader;
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata metadata) {
|
||||
// Find all possible auto configuration classes, filtering duplicates
|
||||
List<String> factories = new ArrayList<String>(new LinkedHashSet<String>(
|
||||
SpringFactoriesLoader.loadFactoryNames(EndpointWebMvcConfiguration.class,
|
||||
this.beanClassLoader)));
|
||||
this.classLoader)));
|
||||
return factories.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
beanClassLoader = classLoader;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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
|
||||
*
|
||||
* http://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.autoconfigure;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Provides access to the {@link ApplicationContext} being used to manage actuator
|
||||
* endpoints.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class ManagementContextResolver {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
ManagementContextResolver(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all {@link MvcEndpoints} from the management context.
|
||||
* @return {@link MvcEndpoints} from the management context
|
||||
*/
|
||||
public MvcEndpoints getMvcEndpoints() {
|
||||
try {
|
||||
return getApplicationContext().getBean(MvcEndpoints.class);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the management {@link ApplicationContext}
|
||||
* @return the management {@link ApplicationContext}
|
||||
*/
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration.ManagementContextResolver;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
@@ -259,10 +258,10 @@ public class ManagementSecurityAutoConfiguration {
|
||||
if (!this.management.getSecurity().isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
String path = management.getContextPath();
|
||||
String path = this.management.getContextPath();
|
||||
if (StringUtils.hasText(path)) {
|
||||
AntPathRequestMatcher matcher = new AntPathRequestMatcher(
|
||||
server.getPath(path) + "/**");
|
||||
this.server.getPath(path) + "/**");
|
||||
return matcher;
|
||||
}
|
||||
return new EndpointPathRequestMatcher();
|
||||
@@ -297,30 +296,36 @@ public class ManagementSecurityAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
if (endpointHandlerMapping == null && contextResolver != null) {
|
||||
ApplicationContext context = contextResolver.getApplicationContext();
|
||||
EndpointHandlerMapping endpointMapping = ManagementWebSecurityConfigurerAdapter.this.endpointHandlerMapping;
|
||||
if (endpointMapping == null
|
||||
&& ManagementWebSecurityConfigurerAdapter.this.contextResolver != null) {
|
||||
ApplicationContext context = ManagementWebSecurityConfigurerAdapter.this.contextResolver
|
||||
.getApplicationContext();
|
||||
if (context != null
|
||||
&& context.getBeanNamesForType(EndpointHandlerMapping.class).length > 0) {
|
||||
endpointHandlerMapping = context
|
||||
ManagementWebSecurityConfigurerAdapter.this.endpointHandlerMapping = context
|
||||
.getBean(EndpointHandlerMapping.class);
|
||||
}
|
||||
}
|
||||
if (endpointHandlerMapping == null) {
|
||||
endpointHandlerMapping = new EndpointHandlerMapping(
|
||||
if (endpointMapping == null) {
|
||||
ManagementWebSecurityConfigurerAdapter.this.endpointHandlerMapping = new EndpointHandlerMapping(
|
||||
Collections.<MvcEndpoint> emptySet());
|
||||
}
|
||||
if (delegate == null) {
|
||||
if (this.delegate == null) {
|
||||
List<RequestMatcher> pathMatchers = new ArrayList<RequestMatcher>();
|
||||
String[] paths = !sensitive ? getEndpointPaths(
|
||||
endpointHandlerMapping, false)
|
||||
: getEndpointPaths(endpointHandlerMapping);
|
||||
String[] paths = !this.sensitive ? getEndpointPaths(
|
||||
endpointMapping,
|
||||
false)
|
||||
: getEndpointPaths(endpointMapping);
|
||||
for (String path : paths) {
|
||||
pathMatchers.add(new AntPathRequestMatcher(server.getPath(path)));
|
||||
pathMatchers.add(new AntPathRequestMatcher(
|
||||
ManagementWebSecurityConfigurerAdapter.this.server
|
||||
.getPath(path)));
|
||||
}
|
||||
delegate = pathMatchers.isEmpty() ? AnyRequestMatcher.INSTANCE
|
||||
this.delegate = pathMatchers.isEmpty() ? AnyRequestMatcher.INSTANCE
|
||||
: new OrRequestMatcher(pathMatchers);
|
||||
}
|
||||
return delegate.matches(request);
|
||||
return this.delegate.matches(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ManagementServerProperties implements SecurityPrerequisite {
|
||||
public static final int ACCESS_OVERRIDE_ORDER = ManagementServerProperties.BASIC_AUTH_ORDER - 1;
|
||||
|
||||
/**
|
||||
* Management endpoint HTTP port. Use the same port as the applicationby default.
|
||||
* Management endpoint HTTP port. Use the same port as the application by default.
|
||||
*/
|
||||
private Integer port;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.web.context.WebApplicationContext;
|
||||
* main context.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
* @see ConditionalOnManagementMvcContext
|
||||
*/
|
||||
class OnManagementMvcCondition extends SpringBootCondition {
|
||||
|
||||
@@ -74,18 +74,17 @@ class OnManagementMvcCondition extends SpringBootCondition {
|
||||
if ((managementPort == null)
|
||||
|| (serverPort == null && managementPort.equals(8080))
|
||||
|| (managementPort != 0 && managementPort.equals(serverPort))) {
|
||||
return new ConditionOutcome(true,
|
||||
"The main context is the management context");
|
||||
return ConditionOutcome.match("The main context is the management context");
|
||||
}
|
||||
return new ConditionOutcome(false,
|
||||
"The main context is not the management context");
|
||||
return ConditionOutcome.noMatch("The main context is not the management context");
|
||||
}
|
||||
|
||||
private <T> T getBeanCarefully(ConditionContext context, Class<T> type) {
|
||||
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
context.getBeanFactory(), type, false, false);
|
||||
if (names.length == 1) {
|
||||
BeanDefinition original = findBeanDefinition(context.getBeanFactory(), names[0]);
|
||||
BeanDefinition original = findBeanDefinition(context.getBeanFactory(),
|
||||
names[0]);
|
||||
if (original instanceof RootBeanDefinition) {
|
||||
DefaultListableBeanFactory temp = new DefaultListableBeanFactory();
|
||||
temp.setParentBeanFactory(context.getBeanFactory());
|
||||
@@ -100,16 +99,19 @@ class OnManagementMvcCondition extends SpringBootCondition {
|
||||
return null;
|
||||
}
|
||||
|
||||
private BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory, String name) {
|
||||
private BeanDefinition findBeanDefinition(
|
||||
ConfigurableListableBeanFactory beanFactory, String name) {
|
||||
BeanDefinition original = null;
|
||||
while (beanFactory!=null && original==null){
|
||||
while (beanFactory != null && original == null) {
|
||||
if (beanFactory.containsLocalBean(name)) {
|
||||
original = beanFactory.getBeanDefinition(name);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
|
||||
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
beanFactory = (ConfigurableListableBeanFactory) parentBeanFactory;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
beanFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.util.Set;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
@@ -52,8 +52,9 @@ public class MvcEndpoints implements ApplicationContextAware, InitializingBean {
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Collection<MvcEndpoint> existing = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
this.applicationContext, MvcEndpoint.class).values();
|
||||
Collection<MvcEndpoint> existing = BeanFactoryUtils
|
||||
.beansOfTypeIncludingAncestors(this.applicationContext, MvcEndpoint.class)
|
||||
.values();
|
||||
this.endpoints.addAll(existing);
|
||||
this.customTypes = findEndpointClasses(existing);
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
||||
@@ -16,18 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
@@ -42,7 +30,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration.ManagementContextResolver;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer;
|
||||
@@ -84,6 +71,18 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link EndpointWebMvcAutoConfiguration}.
|
||||
*
|
||||
@@ -245,7 +244,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
||||
this.applicationContext.register(RootConfig.class, BaseConfiguration.class,
|
||||
ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class);
|
||||
new ServerPortInfoApplicationContextInitializer()
|
||||
.initialize(this.applicationContext);
|
||||
.initialize(this.applicationContext);
|
||||
this.applicationContext.refresh();
|
||||
Integer localServerPort = this.applicationContext.getEnvironment().getProperty(
|
||||
"local.server.port", Integer.class);
|
||||
@@ -261,7 +260,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
||||
@Test
|
||||
public void portPropertiesOnDifferentPort() throws Exception {
|
||||
new ServerPortInfoApplicationContextInitializer()
|
||||
.initialize(this.applicationContext);
|
||||
.initialize(this.applicationContext);
|
||||
this.applicationContext.register(RootConfig.class, DifferentPortConfig.class,
|
||||
BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class);
|
||||
@@ -422,12 +421,12 @@ public class EndpointWebMvcAutoConfigurationTests {
|
||||
|
||||
@Configuration
|
||||
@Import({ PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedServletContainerAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ManagementServerPropertiesAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class, WebMvcAutoConfiguration.class })
|
||||
EmbeddedServletContainerAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ManagementServerPropertiesAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class, WebMvcAutoConfiguration.class })
|
||||
protected static class BaseConfiguration {
|
||||
|
||||
}
|
||||
@@ -585,7 +584,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
||||
}
|
||||
|
||||
private static class GrabManagementPort implements
|
||||
ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
|
||||
private ApplicationContext rootContext;
|
||||
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.mvc;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -43,6 +37,12 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for {@link EnvironmentMvcEndpoint}
|
||||
*
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.mvc;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -47,6 +41,12 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for {@link MetricsMvcEndpoint}
|
||||
*
|
||||
|
||||
@@ -75,8 +75,8 @@ public class ResourceProperties implements ResourceLoaderAware {
|
||||
private final Chain chain = new Chain();
|
||||
|
||||
/**
|
||||
* Locations of static resources. Defaults to classpath:[/META-INF/resources/, /resources/, /static/, /public/]
|
||||
* plus context:/ (the root of the servlet context).
|
||||
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
|
||||
* /resources/, /static/, /public/] plus context:/ (the root of the servlet context).
|
||||
*/
|
||||
private String[] staticLocations = RESOURCE_LOCATIONS;
|
||||
|
||||
@@ -267,9 +267,9 @@ public class ResourceProperties implements ResourceLoaderAware {
|
||||
}
|
||||
|
||||
private String[] getStaticWelcomePageLocations() {
|
||||
String[] result = new String[staticLocations.length];
|
||||
String[] result = new String[this.staticLocations.length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
String location = staticLocations[i];
|
||||
String location = this.staticLocations[i];
|
||||
if (!location.endsWith("/")) {
|
||||
location = location + "/";
|
||||
}
|
||||
@@ -281,7 +281,7 @@ public class ResourceProperties implements ResourceLoaderAware {
|
||||
public List<Resource> getFaviconLocations() {
|
||||
List<Resource> locations = new ArrayList<Resource>(
|
||||
CLASSPATH_RESOURCE_LOCATIONS.length + 1);
|
||||
if (resourceLoader != null) {
|
||||
if (this.resourceLoader != null) {
|
||||
for (String location : CLASSPATH_RESOURCE_LOCATIONS) {
|
||||
locations.add(this.resourceLoader.getResource(location));
|
||||
}
|
||||
|
||||
@@ -238,8 +238,10 @@ public class WebMvcAutoConfiguration {
|
||||
.setCachePeriod(cachePeriod));
|
||||
}
|
||||
if (!registry.hasMappingForPattern("/**")) {
|
||||
registerResourceChain(registry.addResourceHandler("/**")
|
||||
.addResourceLocations(resourceProperties.getStaticLocations())
|
||||
registerResourceChain(registry
|
||||
.addResourceHandler("/**")
|
||||
.addResourceLocations(
|
||||
this.resourceProperties.getStaticLocations())
|
||||
.setCachePeriod(cachePeriod));
|
||||
}
|
||||
}
|
||||
@@ -282,7 +284,7 @@ public class WebMvcAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
Resource page = resourceProperties.getWelcomePage();
|
||||
Resource page = this.resourceProperties.getWelcomePage();
|
||||
if (page != null) {
|
||||
logger.info("Adding welcome page: " + page);
|
||||
registry.addViewController("/").setViewName("forward:index.html");
|
||||
@@ -308,7 +310,8 @@ public class WebMvcAutoConfiguration {
|
||||
@Bean
|
||||
public ResourceHttpRequestHandler faviconRequestHandler() {
|
||||
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
|
||||
requestHandler.setLocations(resourceProperties.getFaviconLocations());
|
||||
requestHandler
|
||||
.setLocations(this.resourceProperties.getFaviconLocations());
|
||||
return requestHandler;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -37,6 +34,9 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for welcome page using {@link MockMvc} and {@link SpringJUnit4ClassRunner}.
|
||||
*
|
||||
@@ -50,14 +50,14 @@ public class WelcomePageMockMvcTests {
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (wac != null) {
|
||||
wac.close();
|
||||
if (this.wac != null) {
|
||||
this.wac.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void homePageNotFound() throws Exception {
|
||||
wac = (ConfigurableWebApplicationContext) new SpringApplicationBuilder(
|
||||
this.wac = (ConfigurableWebApplicationContext) new SpringApplicationBuilder(
|
||||
TestConfiguration.class).run();
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
this.mockMvc.perform(get("/")).andExpect(status().isNotFound()).andReturn();
|
||||
@@ -65,7 +65,7 @@ public class WelcomePageMockMvcTests {
|
||||
|
||||
@Test
|
||||
public void homePageCustomLocation() throws Exception {
|
||||
wac = (ConfigurableWebApplicationContext) new SpringApplicationBuilder(
|
||||
this.wac = (ConfigurableWebApplicationContext) new SpringApplicationBuilder(
|
||||
TestConfiguration.class).properties(
|
||||
"spring.resources.staticLocations:classpath:/custom/").run();
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
@@ -74,8 +74,9 @@ public class WelcomePageMockMvcTests {
|
||||
|
||||
@Test
|
||||
public void homePageCustomLocationNoTrailingSlash() throws Exception {
|
||||
wac = (ConfigurableWebApplicationContext) new SpringApplicationBuilder(
|
||||
TestConfiguration.class).properties("spring.resources.staticLocations:classpath:/custom").run();
|
||||
this.wac = (ConfigurableWebApplicationContext) new SpringApplicationBuilder(
|
||||
TestConfiguration.class).properties(
|
||||
"spring.resources.staticLocations:classpath:/custom").run();
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
this.mockMvc.perform(get("/")).andExpect(status().isOk()).andReturn();
|
||||
}
|
||||
|
||||
@@ -150,23 +150,23 @@ For example, the following will disable _all_ endpoints except for `info`:
|
||||
endpoints.info.enabled=true
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[production-ready-customizing-endpoints-programmatically]]
|
||||
=== Adding Custom Endpoints
|
||||
If you add a `@Bean` of type `Endpoint` then it will automatically be exposed over JMX and
|
||||
HTTP (if there is an server available). An HTTP endpoints can be customized further by
|
||||
creating a bean of type `MvcEndpoint`. Your `MvcEndpoint` is not a `@Controller` but it
|
||||
can use `@RequestMapping` (and `@Managed*`) to expose resources.
|
||||
|
||||
If you add a `@Bean` of type `Endpoint` then it will automatically be
|
||||
exposed over JMX and HTTP (if there is an server available). An HTTP
|
||||
endpoints can be customized further by creating a bean of type
|
||||
`MvcEndpoint`. Your `MvcEndpoint` is not a `@Controller` but it can use
|
||||
`@RequestMapping` (and `@Managed*`) to expose resources.
|
||||
TIP: If you are doing this as a library feature consider adding a configuration class to
|
||||
`/META-INF/spring.factories` under the key
|
||||
`org.springframework.boot.actuate.autoconfigure.EndpointWebMvcConfiguration`. If you do
|
||||
that then the endpoint will move to a child context with all the other MVC endpoints if
|
||||
your users ask for a separate management port or address. A configuration declared this
|
||||
way can be a `WebConfigurerAdapter` if it wants to add static resources (for instance) to
|
||||
the management endpoints.
|
||||
|
||||
TIP: If you are doing this as a library feature consider adding a
|
||||
configuration class to `/META-INF/spring.factories` under the key
|
||||
`org.springframework.boot.actuate.autoconfigure.EndpointWebMvcConfiguration`.
|
||||
If you do that then the endpoint will move to a child context with all
|
||||
the other MVC endpoints if your users ask for a separate management port
|
||||
or address. A configuration declared this way can be a `WebConfigurerAdapter`
|
||||
if it wants to add static resources (for instance) to the management
|
||||
endpoints.
|
||||
|
||||
|
||||
[[production-ready-health]]
|
||||
|
||||
@@ -1175,12 +1175,11 @@ Spring decides not to handle it. Most of the time this will not happen (unless y
|
||||
the default MVC configuration) because Spring will always be able to handle requests
|
||||
through the `DispatcherServlet`.
|
||||
|
||||
You can customize the static resource locations using
|
||||
`spring.resources.staticLocations` (replacing the default values with
|
||||
a list of directory locations). If you do this the default welcome
|
||||
page detection will switch to your custom locations, so if there is an
|
||||
`index.html` in any of your locations on startup, it will be the home
|
||||
page of the application.
|
||||
You can customize the static resource locations using `spring.resources.staticLocations`
|
||||
(replacing the default values with a list of directory locations). If you do this the
|
||||
default welcome page detection will switch to your custom locations, so if there is an
|
||||
`index.html` in any of your locations on startup, it will be the home page of the
|
||||
application.
|
||||
|
||||
In addition to the '`standard`' static resource locations above, a special case is made
|
||||
for http://www.webjars.org/[Webjars content]. Any resources with a path in `+/webjars/**+`
|
||||
|
||||
Reference in New Issue
Block a user