Add EndpointHandlerMappingCustomizer callback
Users can add @Beans of this type to customize the EndpointHandlerMapping (e.g. add interceptors) even if it is in a child context. Fixes gh-1933
This commit is contained in:
parent
1254508357
commit
5d2d39e87d
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
|
|
@ -38,6 +39,7 @@ import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
|||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint;
|
||||
|
|
@ -102,6 +104,9 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
|||
@Autowired
|
||||
private ManagementServerProperties managementServerProperties;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<EndpointHandlerMappingCustomizer> mappingCustomizers;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
|
|
@ -118,6 +123,11 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
|||
if (!disabled) {
|
||||
mapping.setPrefix(this.managementServerProperties.getContextPath());
|
||||
}
|
||||
if (this.mappingCustomizers != null) {
|
||||
for (EndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
|
||||
customizer.customize(mapping);
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
|
@ -29,6 +30,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.ManagementErrorEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
|
||||
|
|
@ -63,6 +65,9 @@ public class EndpointWebMvcChildContextConfiguration {
|
|||
@Value("${error.path:/error}")
|
||||
private String errorPath = "/error";
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<EndpointHandlerMappingCustomizer> mappingCustomizers;
|
||||
|
||||
@Configuration
|
||||
protected static class ServerCustomization implements
|
||||
EmbeddedServletContainerCustomizer {
|
||||
|
|
@ -90,7 +95,7 @@ public class EndpointWebMvcChildContextConfiguration {
|
|||
}
|
||||
// Customize as per the parent context first (so e.g. the access logs go to
|
||||
// the same place)
|
||||
server.customize(container);
|
||||
this.server.customize(container);
|
||||
// Then reset the error pages
|
||||
container.setErrorPages(Collections.<ErrorPage> emptySet());
|
||||
// and add the management-specific bits
|
||||
|
|
@ -130,6 +135,11 @@ public class EndpointWebMvcChildContextConfiguration {
|
|||
EndpointHandlerMapping mapping = new EndpointHandlerMapping(set);
|
||||
// In a child context we definitely want to see the parent endpoints
|
||||
mapping.setDetectHandlerMethodsInAncestorContexts(true);
|
||||
if (this.mappingCustomizers != null) {
|
||||
for (EndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
|
||||
customizer.customize(mapping);
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2012-2014 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.endpoint.mvc;
|
||||
|
||||
/**
|
||||
* Callback for customizing the {@link EndpointHandlerMapping} at configuration time.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface EndpointHandlerMappingCustomizer {
|
||||
|
||||
void customize(EndpointHandlerMapping mapping);
|
||||
|
||||
}
|
||||
|
|
@ -24,11 +24,17 @@ import java.lang.annotation.Target;
|
|||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.autoconfigure.EndpointMvcIntegrationTests.Application;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
|
||||
|
|
@ -39,6 +45,7 @@ import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
|
|||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.boot.test.TestRestTemplate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
|
|
@ -47,7 +54,10 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
|||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
|
@ -66,12 +76,16 @@ public class EndpointMvcIntegrationTests {
|
|||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
@Autowired
|
||||
private TestInterceptor interceptor;
|
||||
|
||||
@Test
|
||||
public void envEndpointNotHidden() {
|
||||
String body = new TestRestTemplate().getForObject("http://localhost:" + this.port
|
||||
+ "/env/user.dir", String.class);
|
||||
assertNotNull(body);
|
||||
assertTrue("Wrong body: \n" + body, body.contains("spring-boot-actuator"));
|
||||
assertEquals(1, this.interceptor.getCount());
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
|
|
@ -104,6 +118,36 @@ public class EndpointMvcIntegrationTests {
|
|||
return Collections.singletonMap("foo", (Object) "bar");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EndpointHandlerMappingCustomizer mappingCustomizer() {
|
||||
return new EndpointHandlerMappingCustomizer() {
|
||||
|
||||
@Override
|
||||
public void customize(EndpointHandlerMapping mapping) {
|
||||
mapping.setInterceptors(new Object[] { interceptor() });
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected TestInterceptor interceptor() {
|
||||
return new TestInterceptor();
|
||||
}
|
||||
}
|
||||
|
||||
protected static class TestInterceptor extends HandlerInterceptorAdapter {
|
||||
private int count = 0;
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, ModelAndView modelAndView) throws Exception {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,17 @@ import java.io.FileNotFoundException;
|
|||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
|
||||
|
|
@ -50,14 +56,18 @@ import org.springframework.http.client.ClientHttpRequest;
|
|||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
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;
|
||||
|
|
@ -122,6 +132,10 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
assertContent("/endpoint", ports.get().server, null);
|
||||
assertContent("/controller", ports.get().management, null);
|
||||
assertContent("/endpoint", ports.get().management, "endpointoutput");
|
||||
List<?> interceptors = (List<?>) ReflectionTestUtils.getField(
|
||||
this.applicationContext.getBean(EndpointHandlerMapping.class),
|
||||
"interceptors");
|
||||
assertEquals(1, interceptors.size());
|
||||
this.applicationContext.close();
|
||||
assertAllClosed();
|
||||
}
|
||||
|
|
@ -350,6 +364,38 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
return properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EndpointHandlerMappingCustomizer mappingCustomizer() {
|
||||
return new EndpointHandlerMappingCustomizer() {
|
||||
|
||||
@Override
|
||||
public void customize(EndpointHandlerMapping mapping) {
|
||||
mapping.setInterceptors(new Object[] { interceptor() });
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected TestInterceptor interceptor() {
|
||||
return new TestInterceptor();
|
||||
}
|
||||
|
||||
protected static class TestInterceptor extends HandlerInterceptorAdapter {
|
||||
private int count = 0;
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler,
|
||||
ModelAndView modelAndView) throws Exception {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
|
|
|||
Loading…
Reference in New Issue