All MVC endpoint paths to be separately customized from the id

This change applies only to "standard" MVC endpoints (not the extended
ones like /env and /jolokia which already have this feature). Allows
users to supply an endpoints.{name}.path.

Fixes gh-2790
pull/4077/merge
Dave Syer 9 years ago
parent 434d46f583
commit 972557851a

@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
public class EndpointMvcAdapter implements MvcEndpoint {
private final Endpoint<?> delegate;
private String path;
/**
* Create a new {@link EndpointMvcAdapter}.
@ -58,7 +59,17 @@ public class EndpointMvcAdapter implements MvcEndpoint {
@Override
public String getPath() {
return "/" + this.delegate.getId();
return this.path != null ? this.path : "/" + this.delegate.getId();
}
public void setPath(String path) {
if (!path.startsWith("/")) {
path = "/" + path;
}
while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
this.path = path;
}
@Override

@ -58,6 +58,8 @@ public class HealthMvcEndpoint implements MvcEndpoint, EnvironmentAware {
private Health cached;
private String path;
public HealthMvcEndpoint(HealthEndpoint delegate) {
this(delegate, true);
}
@ -125,8 +127,9 @@ public class HealthMvcEndpoint implements MvcEndpoint, EnvironmentAware {
public Object invoke(Principal principal) {
if (!this.delegate.isEnabled()) {
// Shouldn't happen because the request mapping should not be registered
return new ResponseEntity<Map<String, String>>(Collections.singletonMap(
"message", "This endpoint is disabled"), HttpStatus.NOT_FOUND);
return new ResponseEntity<Map<String, String>>(
Collections.singletonMap("message", "This endpoint is disabled"),
HttpStatus.NOT_FOUND);
}
Health health = getHealth(principal);
HttpStatus status = getStatus(health);
@ -174,8 +177,8 @@ public class HealthMvcEndpoint implements MvcEndpoint, EnvironmentAware {
}
private boolean isSecure(Principal principal) {
return (principal != null && !principal.getClass().getName()
.contains("Anonymous"));
return (principal != null
&& !principal.getClass().getName().contains("Anonymous"));
}
private boolean isUnrestricted() {
@ -185,7 +188,17 @@ public class HealthMvcEndpoint implements MvcEndpoint, EnvironmentAware {
@Override
public String getPath() {
return "/" + this.delegate.getId();
return this.path != null ? this.path : "/" + this.delegate.getId();
}
public void setPath(String path) {
if (!path.startsWith("/")) {
path = "/" + path;
}
while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
this.path = path;
}
@Override

@ -58,11 +58,18 @@ public class MvcEndpoints implements ApplicationContextAware, InitializingBean {
this.endpoints.addAll(existing);
this.customTypes = findEndpointClasses(existing);
@SuppressWarnings("rawtypes")
Collection<Endpoint> delegates = BeanFactoryUtils.beansOfTypeIncludingAncestors(
this.applicationContext, Endpoint.class).values();
Collection<Endpoint> delegates = BeanFactoryUtils
.beansOfTypeIncludingAncestors(this.applicationContext, Endpoint.class)
.values();
for (Endpoint<?> endpoint : delegates) {
if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) {
this.endpoints.add(new EndpointMvcAdapter(endpoint));
EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);
String path = this.applicationContext.getEnvironment()
.getProperty("endpoints." + endpoint.getId() + ".path");
if (path != null) {
adapter.setPath(path);
}
this.endpoints.add(adapter);
}
}
}

@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.mvc;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.support.StaticApplicationContext;
import static org.junit.Assert.assertEquals;
@ -62,6 +63,19 @@ public class MvcEndpointsTests {
assertEquals(1, this.endpoints.getEndpoints().size());
}
@Test
public void changesPath() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"endpoints.test.path=/foo/bar/");
this.context.getDefaultListableBeanFactory().registerSingleton("endpoint",
new TestEndpoint());
this.endpoints.setApplicationContext(this.context);
this.endpoints.afterPropertiesSet();
assertEquals(1, this.endpoints.getEndpoints().size());
assertEquals("/foo/bar",
this.endpoints.getEndpoints().iterator().next().getPath());
}
protected static class TestEndpoint extends AbstractEndpoint<String> {
public TestEndpoint() {

@ -166,8 +166,6 @@ For example, the following will disable _all_ endpoints except for `info`:
endpoints.info.enabled=true
----
[[production-ready-endpoint-hypermedia]]
=== Hypermedia for actuator MVC endpoints
If http://projects.spring.io/spring-hateoas[Spring HATEOAS] is on the classpath (e.g.
@ -502,7 +500,7 @@ you should carefully consider which endpoints you enable. See
[[production-ready-customizing-management-server-context-path]]
=== Customizing the management server context path
=== Customizing the management endpoint paths
Sometimes it is useful to group all management endpoints under a single path. For example,
your application might already use `/info` for another purpose. You can use the
`management.context-path` property to set a prefix for your management endpoint:
@ -515,6 +513,23 @@ your application might already use `/info` for another purpose. You can use the
The `application.properties` example above will change the endpoint from `/{id}` to
`/manage/{id}` (e.g. `/manage/info`).
You can also change the "id" of an endpoint (using
`endpoints.{name}.id`) which then changes the default resource path
for the MVC endpoint. Legal endpoint ids are composed only of
alphanumeric characters (because they can be exposed in a number of
places, including JMX object names, where special characters are
forbidden). The MVC path can be changed separately by configuring
`endpoints.{name}.path`, and there is no validation on those values
(so you can use anything that is legel in a URL path). For example, to
change the location of the `/health` endpoint to `/ping/me` you can
set `endpoints.health.path=/ping/me`.
TIP: If you provide a custom `MvcEndpoint` remember to include a
settable `path` property, and default it to `/{id}` if you want your
code to behave like the standard MVC endpoints. (Take a look at the
`HealthMvcEndpoint` to see how you might do that.) If your custom
endpoint is an `Endpoint` (not an `MvcEndpoint`) then Spring Boot will
take care of the path for you.
[[production-ready-customizing-management-server-port]]

Loading…
Cancel
Save