Add @EndpointServlet and migrate Jolokia

Add first class support for Servlet based endpoints and rework the
Jolokia endpoint to use it.

Fixes gh-10264
This commit is contained in:
Phillip Webb 2018-01-23 17:15:25 -08:00
parent f8cdc01474
commit 017efda6ec
32 changed files with 1344 additions and 258 deletions

View File

@ -0,0 +1,46 @@
/*
* Copyright 2012-2018 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.endpoint.web;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link ManagementContextConfiguration} for servlet endpoints.
*
* @author Phillip Webb
*
* @since 2.0.0
*/
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
public class ServletEndpointManagementContextConfiguration {
@Bean
public ServletEndpointRegistrar servletEndpointRegistrar(
WebEndpointProperties properties,
ServletEndpointsSupplier servletEndpointsSupplier) {
return new ServletEndpointRegistrar(properties.getBasePath(),
servletEndpointsSupplier.getEndpoints());
}
}

View File

@ -32,6 +32,7 @@ import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor; import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints; import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.PathMapper;
@ -39,12 +40,15 @@ import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer; import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier; import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint; import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer; import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -138,4 +142,20 @@ public class WebEndpointAutoConfiguration {
ExposableControllerEndpoint.class, expose, exclude); ExposableControllerEndpoint.class, expose, exclude);
} }
@ConditionalOnWebApplication(type = Type.SERVLET)
static class WebEndpointServletAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ServletEndpointsSupplier.class)
public ServletEndpointDiscoverer servletEndpointDiscoverer(
ApplicationContext applicationContext, PathMapper webEndpointPathMapper,
ObjectProvider<Collection<OperationInvokerAdvisor>> invokerAdvisors,
ObjectProvider<Collection<EndpointFilter<ExposableServletEndpoint>>> filters) {
return new ServletEndpointDiscoverer(applicationContext,
webEndpointPathMapper,
filters.getIfAvailable(Collections::emptyList));
}
}
} }

View File

@ -0,0 +1,49 @@
/*
* Copyright 2012-2018 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.jolokia;
import java.util.Map;
import java.util.function.Supplier;
import org.jolokia.http.AgentServlet;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
/**
* {@link Endpoint} to expose a Jolokia {@link AgentServlet}.
*
* @author Phillip Webb
* @since 2.0.0
*/
@ServletEndpoint(id = "jolokia")
public class JolokiaEndpoint implements Supplier<EndpointServlet> {
private Map<String, String> initParameters;
public JolokiaEndpoint(Map<String, String> initParameters) {
this.initParameters = initParameters;
}
@Override
public EndpointServlet get() {
return new EndpointServlet(AgentServlet.class)
.withInitParameters(this.initParameters);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2012-2018 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.jolokia;
import org.jolokia.http.AgentServlet;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for the {@link JolokiaEndpoint}.
*
* @author Phillip Webb
* @since 2.0.0
*/
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(AgentServlet.class)
@EnableConfigurationProperties(JolokiaProperties.class)
public class JolokiaEndpointAutoConfiguration {
@Bean
@ConditionalOnEnabledEndpoint
public JolokiaEndpoint jolokiaEndpoint(JolokiaProperties properties) {
return new JolokiaEndpoint(properties.getConfig());
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 2012-2017 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.jolokia;
import org.jolokia.http.AgentServlet;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ManagementServletContext;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.mvc.ServletWrappingController;
/**
* {@link ManagementContextConfiguration} for embedding Jolokia, a JMX-HTTP bridge giving
* an alternative to JSR-160 connectors.
* <p>
* This configuration will get automatically enabled as soon as the Jolokia
* {@link AgentServlet} is on the classpath. To disable it set
* {@code management.jolokia.enabled=false}.
* <p>
* Additional configuration parameters for Jolokia can be provided by specifying
* {@code management.jolokia.config.*} properties. See the
* <a href="http://jolokia.org">http://jolokia.org</a> web site for more information on
* supported configuration parameters.
*
* @author Christian Dupuis
* @author Dave Syer
* @author Andy Wilkinson
* @author Madhura Bhave
* @author Stephane Nicoll
* @since 2.0.0
*/
@ManagementContextConfiguration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ AgentServlet.class, ServletWrappingController.class })
@ConditionalOnProperty(value = "management.jolokia.enabled", havingValue = "true")
@EnableConfigurationProperties(JolokiaProperties.class)
public class JolokiaManagementContextConfiguration {
private final ManagementServletContext managementServletContext;
private final JolokiaProperties properties;
public JolokiaManagementContextConfiguration(
ManagementServletContext managementServletContext,
JolokiaProperties properties) {
this.managementServletContext = managementServletContext;
this.properties = properties;
}
@Bean
public ServletRegistrationBean<AgentServlet> jolokiaServlet() {
String path = this.managementServletContext.getServletPath()
+ this.properties.getPath();
String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*");
ServletRegistrationBean<AgentServlet> registration = new ServletRegistrationBean<>(
new AgentServlet(), urlMapping);
registration.setInitParameters(this.properties.getConfig());
return registration;
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,41 +29,15 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 2.0.0 * @since 2.0.0
*/ */
@ConfigurationProperties(prefix = "management.jolokia") @ConfigurationProperties(prefix = "management.endpoint.jolokia")
public class JolokiaProperties { public class JolokiaProperties {
/**
* Whether to enable Jolokia.
*/
private boolean enabled;
/**
* Path at which Jolokia is available.
*/
private String path = "/jolokia";
/** /**
* Jolokia settings. These are traditionally set using servlet parameters. Refer to * Jolokia settings. These are traditionally set using servlet parameters. Refer to
* the documentation of Jolokia for more details. * the documentation of Jolokia for more details.
*/ */
private final Map<String, String> config = new HashMap<>(); private final Map<String, String> config = new HashMap<>();
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getPath() {
return this.path;
}
public void setPath(String path) {
this.path = path;
}
public Map<String, String> getConfig() { public Map<String, String> getConfig() {
return this.config; return this.config;
} }

View File

@ -795,7 +795,7 @@
"type": "java.lang.String", "type": "java.lang.String",
"description": "Endpoint URL path.", "description": "Endpoint URL path.",
"deprecation": { "deprecation": {
"reason": "Endpoint path is no longer customizable.", "replacement": "management.endpoints.web.path-mapping.jolokia",
"level": "error" "level": "error"
} }
}, },
@ -1734,4 +1734,3 @@
} }
] ]
} }

View File

@ -23,6 +23,7 @@ org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfigura
org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.jms.JmsHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.jms.JmsHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ldap.LdapHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ldap.LdapHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.liquibase.LiquibaseEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.liquibase.LiquibaseEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration,\
@ -47,10 +48,10 @@ org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoC
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\ org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\
org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey.JerseyWebEndpointManagementContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey.JerseyWebEndpointManagementContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaManagementContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.web.jersey.JerseyManagementChildContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.web.jersey.JerseyManagementChildContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementChildContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementChildContextConfiguration,\

View File

@ -0,0 +1,69 @@
/*
* Copyright 2012-2018 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.endpoint.web;
import java.util.Collections;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ServletEndpointManagementContextConfiguration}.
*
* @author Phillip Webb
*/
public class ServletEndpointManagementContextConfigurationTests {
private WebApplicationContextRunner runner = new WebApplicationContextRunner()
.withUserConfiguration(TestConfig.class);
@Test
public void contextShouldContainServletEndpointRegistrar() {
this.runner.run((context) -> assertThat(context)
.hasSingleBean(ServletEndpointRegistrar.class));
}
@Test
public void contextWhenNoServletBasedShouldNotContainServletEndpointRegistrar() {
new ApplicationContextRunner().withUserConfiguration(TestConfig.class)
.run((context) -> assertThat(context)
.doesNotHaveBean(ServletEndpointRegistrar.class));
}
@Configuration
@Import(ServletEndpointManagementContextConfiguration.class)
@EnableConfigurationProperties(WebEndpointProperties.class)
static class TestConfig {
@Bean
public ServletEndpointsSupplier servletEndpointsSupplier() {
return () -> Collections.emptyList();
}
}
}

View File

@ -24,8 +24,10 @@ import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer; import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer; import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -35,12 +37,15 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Yunkun Huang * @author Yunkun Huang
* @author Phillip Webb
*/ */
public class WebEndpointAutoConfigurationTests { public class WebEndpointAutoConfigurationTests {
private static final AutoConfigurations CONFIGURATIONS = AutoConfigurations
.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class);
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(EndpointAutoConfiguration.class, .withConfiguration(CONFIGURATIONS);
WebEndpointAutoConfiguration.class));
@Test @Test
public void webApplicationConfiguresEndpointMediaTypes() { public void webApplicationConfiguresEndpointMediaTypes() {
@ -82,4 +87,18 @@ public class WebEndpointAutoConfigurationTests {
}); });
} }
@Test
public void contextShouldConfigureServletEndpointDiscoverer() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(ServletEndpointDiscoverer.class);
});
}
@Test
public void contextWhenNotServletShouldNotConfigureServletEndpointDiscoverer() {
new ApplicationContextRunner().withConfiguration(CONFIGURATIONS)
.run((context) -> assertThat(context)
.doesNotHaveBean(ServletEndpointDiscoverer.class));
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,8 +27,10 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaEndpoint;
import org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
@ -53,14 +55,14 @@ import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Integration tests for {@link JolokiaManagementContextConfiguration}. * Integration tests for {@link JolokiaEndpoint}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext @DirtiesContext
@TestPropertySource(properties = "management.jolokia.enabled=true") @TestPropertySource(properties = "management.endpoints.web.expose=jolokia")
public class JolokiaManagementContextConfigurationIntegrationTests { public class JolokiaManagementContextConfigurationIntegrationTests {
@Autowired @Autowired
@ -70,7 +72,7 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
public void jolokiaIsExposed() { public void jolokiaIsExposed() {
ResponseEntity<String> response = this.restTemplate ResponseEntity<String> response = this.restTemplate
.getForEntity("/actuator/jolokia", String.class); .getForEntity("/actuator/jolokia", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode()); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("\"agent\""); assertThat(response.getBody()).contains("\"agent\"");
assertThat(response.getBody()).contains("\"request\":{\"type\""); assertThat(response.getBody()).contains("\"request\":{\"type\"");
} }
@ -79,7 +81,7 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
public void search() { public void search() {
ResponseEntity<String> response = this.restTemplate ResponseEntity<String> response = this.restTemplate
.getForEntity("/actuator/jolokia/search/java.lang:*", String.class); .getForEntity("/actuator/jolokia/search/java.lang:*", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode()); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("GarbageCollector"); assertThat(response.getBody()).contains("GarbageCollector");
} }
@ -87,7 +89,7 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
public void read() { public void read() {
ResponseEntity<String> response = this.restTemplate.getForEntity( ResponseEntity<String> response = this.restTemplate.getForEntity(
"/actuator/jolokia/read/java.lang:type=Memory", String.class); "/actuator/jolokia/read/java.lang:type=Memory", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode()); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("NonHeapMemoryUsage"); assertThat(response.getBody()).contains("NonHeapMemoryUsage");
} }
@ -95,18 +97,19 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
public void list() { public void list() {
ResponseEntity<String> response = this.restTemplate.getForEntity( ResponseEntity<String> response = this.restTemplate.getForEntity(
"/actuator/jolokia/list/java.lang/type=Memory/attr", String.class); "/actuator/jolokia/list/java.lang/type=Memory/attr", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode()); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("NonHeapMemoryUsage"); assertThat(response.getBody()).contains("NonHeapMemoryUsage");
} }
@Configuration @Configuration
@MinimalWebConfiguration @MinimalWebConfiguration
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
JolokiaEndpointAutoConfiguration.class, EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class, ServletManagementContextAutoConfiguration.class,
ManagementContextAutoConfiguration.class, ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class }) ServletEndpointManagementContextConfiguration.class })
protected static class Application { protected static class Application {
} }

View File

@ -0,0 +1,108 @@
/*
* Copyright 2012-2018 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.jolokia;
import java.util.Collection;
import java.util.Collections;
import org.jolokia.http.AgentServlet;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JolokiaEndpointAutoConfiguration}.
*
* @author Christian Dupuis
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class JolokiaEndpointAutoConfigurationTests {
private final WebApplicationContextRunner runner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
ServletEndpointManagementContextConfiguration.class,
JolokiaEndpointAutoConfiguration.class, TestConfiguration.class));
@Test
public void jolokiaServletShouldBeEnabledByDefault() {
this.runner.run((context) -> {
ExposableServletEndpoint endpoint = getEndpoint(context);
assertThat(endpoint.getRootPath()).isEqualTo("jolokia");
Object servlet = ReflectionTestUtils.getField(endpoint.getEndpointServlet(),
"servlet");
assertThat(servlet).isInstanceOf(AgentServlet.class);
});
}
@Test
public void jolokiaServletWhenDisabledShouldNotBeDiscovered() {
this.runner.withPropertyValues("management.endpoint.jolokia.enabled=false")
.run((context) -> {
Collection<ExposableServletEndpoint> endpoints = context
.getBean(ServletEndpointsSupplier.class).getEndpoints();
assertThat(endpoints).isEmpty();
});
}
@Test
public void jolokiaServletWhenHasCustomConfigShouldApplyInitParams() {
this.runner.withPropertyValues("management.endpoint.jolokia.config.debug=true")
.run((context) -> {
ExposableServletEndpoint endpoint = getEndpoint(context);
assertThat(endpoint.getEndpointServlet()).extracting("initParameters")
.containsOnly(Collections.singletonMap("debug", "true"));
});
}
private ExposableServletEndpoint getEndpoint(
AssertableWebApplicationContext context) {
Collection<ExposableServletEndpoint> endpoints = context
.getBean(ServletEndpointsSupplier.class).getEndpoints();
return endpoints.iterator().next();
}
@Configuration
static class TestConfiguration {
@Bean
public ServletEndpointDiscoverer servletEndpointDiscoverer(
ApplicationContext applicationContext) {
return new ServletEndpointDiscoverer(applicationContext,
PathMapper.useEndpointId(), Collections.emptyList());
}
}
}

View File

@ -1,105 +0,0 @@
/*
* Copyright 2012-2017 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.jolokia;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link JolokiaManagementContextConfiguration}.
*
* @author Christian Dupuis
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class JolokiaManagementContextConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
JolokiaManagementContextConfiguration.class));
@Test
public void jolokiaCanBeEnabled() {
this.contextRunner.withPropertyValues("management.jolokia.enabled=true")
.run((context) -> {
context.getBean(ServletRegistrationBean.class);
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
ServletRegistrationBean<?> registrationBean = context
.getBean(ServletRegistrationBean.class);
assertThat(registrationBean.getUrlMappings())
.contains("/actuator/jolokia/*");
assertThat(registrationBean.getInitParameters()).isEmpty();
});
}
@Test
public void jolokiaIsDisabledByDefault() {
this.contextRunner.run((context) -> assertThat(context)
.doesNotHaveBean(ServletRegistrationBean.class));
}
@Test
public void customPath() {
this.contextRunner
.withPropertyValues("management.jolokia.enabled=true",
"management.jolokia.path=/lokia")
.run(isDefinedOnPath("/actuator/lokia/*"));
}
@Test
public void customManagementPath() {
this.contextRunner
.withPropertyValues("management.jolokia.enabled=true",
"management.endpoints.web.base-path=/admin")
.run(isDefinedOnPath("/admin/jolokia/*"));
}
@Test
public void customInitParameters() {
this.contextRunner.withPropertyValues("management.jolokia.enabled=true",
"management.jolokia.config.debug=true").run((context) -> {
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
ServletRegistrationBean<?> registrationBean = context
.getBean(ServletRegistrationBean.class);
assertThat(registrationBean.getInitParameters())
.containsOnly(entry("debug", "true"));
});
}
private ContextConsumer<AssertableWebApplicationContext> isDefinedOnPath(
String path) {
return (context) -> {
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
ServletRegistrationBean<?> registrationBean = context
.getBean(ServletRegistrationBean.class);
assertThat(registrationBean.getUrlMappings()).containsExactly(path);
};
}
}

View File

@ -291,6 +291,9 @@ public abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O exten
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private boolean isFilterMatch(Class<?> filter, EndpointBean endpointBean) { private boolean isFilterMatch(Class<?> filter, EndpointBean endpointBean) {
if (!isEndpointExposed(endpointBean.getBean())) {
return false;
}
if (filter == null) { if (filter == null) {
return true; return true;
} }

View File

@ -25,6 +25,11 @@ package org.springframework.boot.actuate.endpoint.invoke;
@FunctionalInterface @FunctionalInterface
public interface ParameterValueMapper { public interface ParameterValueMapper {
/**
* A {@link ParameterValueMapper} that does nothing.
*/
ParameterValueMapper NONE = (paramere, value) -> value;
/** /**
* Map the specified {@code input} parameter to the given {@code parameterType}. * Map the specified {@code input} parameter to the given {@code parameterType}.
* @param parameter the parameter to map * @param parameter the parameter to map

View File

@ -0,0 +1,81 @@
/*
* Copyright 2012-2018 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.web;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Servlet;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Contains details of a servlet that is exposed as an actuator endpoint.
*
* @author Phillip Webb
*/
public final class EndpointServlet {
private final Servlet servlet;
private final Map<String, String> initParameters;
public EndpointServlet(Class<? extends Servlet> servlet) {
Assert.notNull(servlet, "Servlet must not be null");
this.servlet = BeanUtils.instantiateClass(servlet);
this.initParameters = Collections.emptyMap();
}
public EndpointServlet(Servlet servlet) {
Assert.notNull(servlet, "Servlet must not be null");
this.servlet = servlet;
this.initParameters = Collections.emptyMap();
}
private EndpointServlet(Servlet servlet, Map<String, String> initParameters) {
this.servlet = servlet;
this.initParameters = Collections.unmodifiableMap(initParameters);
}
public EndpointServlet withInitParameter(String name, String value) {
Assert.hasText(name, "Name must not be empty");
return withInitParameters(Collections.singletonMap(name, value));
}
public EndpointServlet withInitParameters(Map<String, String> initParameters) {
Assert.notNull(initParameters, "InitParameters must not be null");
boolean hasEmptyKey = initParameters.values().stream()
.anyMatch((key) -> !StringUtils.hasText(key));
Assert.isTrue(!hasEmptyKey, "InitParameters must not contain empty keys");
Map<String, String> mergedInitParameters = new LinkedHashMap<>(
this.initParameters);
mergedInitParameters.putAll(initParameters);
return new EndpointServlet(this.servlet, mergedInitParameters);
}
Servlet getServlet() {
return this.servlet;
}
Map<String, String> getInitParameters() {
return this.initParameters;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2012-2018 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.web;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.Operation;
/**
* Information describing an endpoint that can be exposed by registering a servlet.
*
* @author Phillip Webb
* @since 2.0.0
*/
public interface ExposableServletEndpoint
extends ExposableEndpoint<Operation>, PathMappedEndpoint {
/**
* Return details of the servlet that should registered.
* @return the endpoint servlet
*/
EndpointServlet getEndpointServlet();
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012-2018 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.web;
import java.util.Collection;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.util.Assert;
/**
* {@link ServletContextInitializer} to register {@link ExposableServletEndpoint} servlet
* endpoints.
*
* @author Phillip Webb
* @since 2.0.0
*/
public class ServletEndpointRegistrar implements ServletContextInitializer {
private static final Log logger = LogFactory.getLog(ServletEndpointRegistrar.class);
private final String basePath;
private final Collection<ExposableServletEndpoint> servletEndpoints;
public ServletEndpointRegistrar(String basePath,
Collection<ExposableServletEndpoint> servletEndpoints) {
Assert.notNull(servletEndpoints, "ServletEndpoints must not be null");
this.basePath = (basePath == null ? "" : basePath);
this.servletEndpoints = servletEndpoints;
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
this.servletEndpoints.forEach((servletEndpoint) -> {
register(servletContext, servletEndpoint);
});
}
private void register(ServletContext servletContext,
ExposableServletEndpoint endpoint) {
String name = endpoint.getId() + "-actuator-endpoint";
String path = this.basePath + "/" + endpoint.getRootPath();
String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*");
EndpointServlet endpointServlet = endpoint.getEndpointServlet();
Dynamic registration = servletContext.addServlet(name,
endpointServlet.getServlet());
registration.addMapping(urlMapping);
registration.setInitParameters(endpointServlet.getInitParameters());
logger.info("Registered '" + path + "' to " + name);
}
}

View File

@ -25,8 +25,6 @@ import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;
import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameter;
import org.springframework.boot.actuate.endpoint.invoke.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -54,7 +52,7 @@ public class ControllerEndpointDiscoverer
public ControllerEndpointDiscoverer(ApplicationContext applicationContext, public ControllerEndpointDiscoverer(ApplicationContext applicationContext,
PathMapper endpointPathMapper, PathMapper endpointPathMapper,
Collection<EndpointFilter<ExposableControllerEndpoint>> filters) { Collection<EndpointFilter<ExposableControllerEndpoint>> filters) {
super(applicationContext, new NoOpParameterValueMapper(), Collections.emptyList(), super(applicationContext, ParameterValueMapper.NONE, Collections.emptyList(),
filters); filters);
Assert.notNull(endpointPathMapper, "EndpointPathMapper must not be null"); Assert.notNull(endpointPathMapper, "EndpointPathMapper must not be null");
this.endpointPathMapper = endpointPathMapper; this.endpointPathMapper = endpointPathMapper;
@ -88,17 +86,4 @@ public class ControllerEndpointDiscoverer
"ControllerEndpoints must not declare operations"); "ControllerEndpoints must not declare operations");
} }
/**
* {@link ParameterValueMapper} that does nothing.
*/
private static class NoOpParameterValueMapper implements ParameterValueMapper {
@Override
public Object mapParameterValue(OperationParameter parameter, Object value)
throws ParameterMappingException {
return value;
}
}
} }

View File

@ -18,13 +18,12 @@ package org.springframework.boot.actuate.endpoint.web.annotation;
import java.util.Collections; import java.util.Collections;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;
/** /**
* A discovered {@link ExposableEndpoint controller endpoint}. * A discovered {@link ExposableControllerEndpoint controller endpoint}.
* *
* @author Phillip Webb * @author Phillip Webb
*/ */

View File

@ -0,0 +1,66 @@
/*
* Copyright 2012-2018 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.web.annotation;
import java.util.Collections;
import java.util.function.Supplier;
import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.util.Assert;
/**
* A discovered {@link ExposableServletEndpoint controller endpoint}.
*
* @author Phillip Webb
*/
class DiscoveredServletEndpoint extends AbstractDiscoveredEndpoint<Operation>
implements ExposableServletEndpoint {
private final String rootPath;
private final EndpointServlet endpointServlet;
DiscoveredServletEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean,
String id, String rootPath, boolean enabledByDefault) {
super(discoverer, endpointBean, id, enabledByDefault, Collections.emptyList());
String beanType = endpointBean.getClass().getName();
Assert.state(endpointBean instanceof Supplier,
() -> "ServletEndpoint bean " + beanType + " must be a supplier");
Object supplied = ((Supplier<?>) endpointBean).get();
Assert.state(supplied != null,
"ServletEndpoint bean " + beanType + " must not supply null");
Assert.state(supplied instanceof EndpointServlet, () -> "ServletEndpoint bean "
+ beanType + " must supply an EndpointServlet");
this.endpointServlet = (EndpointServlet) supplied;
this.rootPath = rootPath;
}
@Override
public String getRootPath() {
return this.rootPath;
}
@Override
public EndpointServlet getEndpointServlet() {
return this.endpointServlet;
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2012-2018 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.web.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.Supplier;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.FilteredEndpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
import org.springframework.core.annotation.AliasFor;
/**
* Identifies a type as being an endpoint that supplies a servlet to expose.
* Implementations must also implement {@link Supplier Supplier&lt;EndpointServlet&gt;}
* and return a valid {@link EndpointServlet}.
* <p>
* This annotation can be used when existing servlets need be be exposed as actuator
* endpoints, but it is at the expense of portability. Most users should prefer the
* {@link Endpoint @Endpoint} or {@link WebEndpoint @WebEndpoint} annotations whenever
* possible.
*
* @author Phillip Webb
* @since 2.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ServletEndpointFilter.class)
public @interface ServletEndpoint {
/**
* The id of the endpoint.
* @return the id
*/
@AliasFor(annotation = Endpoint.class)
String id();
/**
* If the endpoint should be enabled or disabled by default.
* @return {@code true} if the endpoint is enabled by default
*/
@AliasFor(annotation = Endpoint.class)
boolean enableByDefault() default true;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2012-2018 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.web.annotation;
import java.util.Collection;
import java.util.Collections;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;
import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.Assert;
/**
* {@link EndpointDiscoverer} for {@link ExposableServletEndpoint servlet endpoints}.
*
* @author Phillip Webb
* @since 2.0.0
*/
public class ServletEndpointDiscoverer
extends EndpointDiscoverer<ExposableServletEndpoint, Operation>
implements ServletEndpointsSupplier {
private final PathMapper endpointPathMapper;
/**
* Create a new {@link ServletEndpointFilter} instance.
* @param applicationContext the source application context
* @param endpointPathMapper the endpoint path mapper
* @param filters filters to apply
*/
public ServletEndpointDiscoverer(ApplicationContext applicationContext,
PathMapper endpointPathMapper,
Collection<EndpointFilter<ExposableServletEndpoint>> filters) {
super(applicationContext, ParameterValueMapper.NONE, Collections.emptyList(),
filters);
Assert.notNull(endpointPathMapper, "EndpointPathMapper must not be null");
this.endpointPathMapper = endpointPathMapper;
}
@Override
protected boolean isEndpointExposed(Object endpointBean) {
Class<?> type = endpointBean.getClass();
return AnnotatedElementUtils.isAnnotated(type, ServletEndpoint.class);
}
@Override
protected ExposableServletEndpoint createEndpoint(Object endpointBean, String id,
boolean enabledByDefault, Collection<Operation> operations) {
String rootPath = this.endpointPathMapper.getRootPath(id);
return new DiscoveredServletEndpoint(this, endpointBean, id, rootPath,
enabledByDefault);
}
@Override
protected Operation createOperation(String endpointId,
DiscoveredOperationMethod operationMethod, OperationInvoker invoker) {
throw new IllegalStateException("ServletEndpoints must not declare operations");
}
@Override
protected OperationKey createOperationKey(Operation operation) {
throw new IllegalStateException("ServletEndpoints must not declare operations");
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2012-2018 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.web.annotation;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.annotation.DiscovererEndpointFilter;
/**
* {@link EndpointFilter} for endpoints discovered by {@link ServletEndpointDiscoverer}.
*
* @author Phillip Webb
*/
class ServletEndpointFilter extends DiscovererEndpointFilter {
ServletEndpointFilter() {
super(ServletEndpointDiscoverer.class);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2012-2018 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.web.annotation;
import org.springframework.boot.actuate.endpoint.EndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
/**
* {@link EndpointsSupplier} for {@link ExposableServletEndpoint servlet endpoints}.
*
* @author Phillip Webb
* @since 2.0.0
*/
@FunctionalInterface
public interface ServletEndpointsSupplier
extends EndpointsSupplier<ExposableServletEndpoint> {
}

View File

@ -0,0 +1,119 @@
/*
* Copyright 2012-2018 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.web;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.GenericServlet;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link EndpointServlet}.
*
* @author Phillip Webb
*/
public class EndpointServletTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void createWhenServletClassIsNullShouldThrowException() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Servlet must not be null");
new EndpointServlet((Class<Servlet>) null);
}
@Test
public void createWhenServletIsNullShouldThrowException() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Servlet must not be null");
new EndpointServlet((Servlet) null);
}
@Test
public void createWithServletClassShouldCreateServletInstance() {
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);
assertThat(endpointServlet.getServlet()).isInstanceOf(TestServlet.class);
}
@Test
public void getServletShouldGetServlet() {
TestServlet servlet = new TestServlet();
EndpointServlet endpointServlet = new EndpointServlet(servlet);
assertThat(endpointServlet.getServlet()).isEqualTo(servlet);
}
@Test
public void withInitParameterShouldReturnNewInstance() {
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);
assertThat(endpointServlet.withInitParameter("spring", "boot"))
.isNotSameAs(endpointServlet);
}
@Test
public void withInitParameterWhenHasExistingShouldMergeParameters() {
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class)
.withInitParameter("a", "b").withInitParameter("c", "d");
assertThat(endpointServlet.withInitParameter("a", "b1")
.withInitParameter("e", "f").getInitParameters()).containsExactly(
entry("a", "b1"), entry("c", "d"), entry("e", "f"));
}
@Test
public void withInitParametersShouldCreateNewInstance() {
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);
assertThat(endpointServlet
.withInitParameters(Collections.singletonMap("spring", "boot")))
.isNotSameAs(endpointServlet);
}
@Test
public void withInitParametersWhenHasExistingShouldMergeParameters() {
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class)
.withInitParameter("a", "b").withInitParameter("c", "d");
Map<String, String> extra = new LinkedHashMap<>();
extra.put("a", "b1");
extra.put("e", "f");
assertThat(endpointServlet.withInitParameters(extra).getInitParameters())
.containsExactly(entry("a", "b1"), entry("c", "d"), entry("e", "f"));
}
private static class TestServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
}
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright 2012-2018 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.web;
import java.io.IOException;
import java.util.Collections;
import javax.servlet.GenericServlet;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link ServletEndpointRegistrar}.
*
* @author Phillip Webb
*/
public class ServletEndpointRegistrarTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Mock
private ServletContext servletContext;
@Mock
private Dynamic dynamic;
@Captor
private ArgumentCaptor<Servlet> servlet;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
given(this.servletContext.addServlet(any(String.class), any(Servlet.class)))
.willReturn(this.dynamic);
}
@Test
public void createWhenServletEndpointsIsNullShouldThrowException() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("ServletEndpoints must not be null");
new ServletEndpointRegistrar(null, null);
}
@Test
public void onStartupShouldRegisterServlets() throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class));
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(null,
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
this.servlet.capture());
assertThat(this.servlet.getValue()).isInstanceOf(TestServlet.class);
verify(this.dynamic).addMapping("/test/*");
}
@Test
public void onStartupWhenHasBasePathShouldIncludeBasePath() throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class));
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar("/actuator",
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
this.servlet.capture());
assertThat(this.servlet.getValue()).isInstanceOf(TestServlet.class);
verify(this.dynamic).addMapping("/actuator/test/*");
}
@Test
public void onStartupWhenHasInitParametersShouldRegisterInitParameters()
throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class).withInitParameter("a", "b"));
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar("/actuator",
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.dynamic).setInitParameters(Collections.singletonMap("a", "b"));
}
private ExposableServletEndpoint mockEndpoint(EndpointServlet endpointServlet) {
ExposableServletEndpoint endpoint = mock(ExposableServletEndpoint.class);
given(endpoint.getId()).willReturn("test");
given(endpoint.getEndpointServlet()).willReturn(endpointServlet);
given(endpoint.getRootPath()).willReturn("test");
return endpoint;
}
public static class TestServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
}
}
}

View File

@ -27,6 +27,7 @@ import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.PathMapper;
@ -61,6 +62,7 @@ public class ControllerEndpointDiscovererTests {
assertThat(endpoint.getId()).isEqualTo("testcontroller"); assertThat(endpoint.getId()).isEqualTo("testcontroller");
assertThat(endpoint.getController()) assertThat(endpoint.getController())
.isInstanceOf(TestControllerEndpoint.class); .isInstanceOf(TestControllerEndpoint.class);
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
}); });
} }

View File

@ -0,0 +1,212 @@
/*
* Copyright 2012-2018 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.web.annotation;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ServletEndpointDiscoverer}.
*
* @author Phillip Webb
*/
public class ServletEndpointDiscovererTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Test
public void getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {
load(EmptyConfiguration.class,
(discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty());
}
@Test
public void getEndpointsShouldIncludeServletEndpoints() {
load(TestServletEndpoint.class, (discoverer) -> {
Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();
assertThat(endpoints).hasSize(1);
ExposableServletEndpoint endpoint = endpoints.iterator().next();
assertThat(endpoint.getId()).isEqualTo("testservlet");
assertThat(endpoint.getEndpointServlet()).isNotNull();
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
});
}
@Test
public void getEndpointsShouldNotDiscoverRegularEndpoints() {
load(WithRegularEndpointConfiguration.class, (discoverer) -> {
Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();
List<String> ids = endpoints.stream().map(ExposableEndpoint::getId)
.collect(Collectors.toList());
assertThat(ids).containsOnly("testservlet");
});
}
@Test
public void getEndpointWhenEndpointHasOperationsShouldThrowException() {
load(TestServletEndpointWithOperation.class, (discoverer) -> {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("ServletEndpoints must not declare operations");
discoverer.getEndpoints();
});
}
@Test
public void getEndpointWhenEndpointNotASupplierShouldThrowException() {
load(TestServletEndpointNotASupplier.class, (discoverer) -> {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("must be a supplier");
discoverer.getEndpoints();
});
}
@Test
public void getEndpointWhenEndpointSuppliesWrongTypeShouldThrowException() {
load(TestServletEndpointSupplierOfWrongType.class, (discoverer) -> {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("must supply an EndpointServlet");
discoverer.getEndpoints();
});
}
@Test
public void getEndpointWhenEndpoinSuppliesNullShouldThrowException() {
load(TestServletEndpointSupplierOfNull.class, (discoverer) -> {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("must not supply null");
discoverer.getEndpoints();
});
}
private void load(Class<?> configuration,
Consumer<ServletEndpointDiscoverer> consumer) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
configuration);
try {
ServletEndpointDiscoverer discoverer = new ServletEndpointDiscoverer(context,
PathMapper.useEndpointId(), Collections.emptyList());
consumer.accept(discoverer);
}
finally {
context.close();
}
}
@Configuration
static class EmptyConfiguration {
}
@Configuration
@Import({ TestEndpoint.class, TestServletEndpoint.class })
static class WithRegularEndpointConfiguration {
}
@ServletEndpoint(id = "testservlet")
static class TestServletEndpoint implements Supplier<EndpointServlet> {
@Override
public EndpointServlet get() {
return new EndpointServlet(TestServlet.class);
}
}
@Endpoint(id = "test")
static class TestEndpoint {
}
@ServletEndpoint(id = "testservlet")
static class TestServletEndpointWithOperation implements Supplier<EndpointServlet> {
@Override
public EndpointServlet get() {
return new EndpointServlet(TestServlet.class);
}
@ReadOperation
public String read() {
return "error";
}
}
private static class TestServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
}
}
@ServletEndpoint(id = "testservlet")
static class TestServletEndpointNotASupplier {
}
@ServletEndpoint(id = "testservlet")
static class TestServletEndpointSupplierOfWrongType implements Supplier<String> {
@Override
public String get() {
return "error";
}
}
@ServletEndpoint(id = "testservlet")
static class TestServletEndpointSupplierOfNull implements Supplier<EndpointServlet> {
@Override
public EndpointServlet get() {
return null;
}
}
}

View File

@ -1258,6 +1258,10 @@ content into your application. Rather, pick only the properties that you need.
management.endpoint.trace.cache.time-to-live=0ms # Maximum time that a response can be cached. management.endpoint.trace.cache.time-to-live=0ms # Maximum time that a response can be cached.
management.endpoint.trace.enabled= # Whether to enable the trace endpoint. management.endpoint.trace.enabled= # Whether to enable the trace endpoint.
# JOLOKIA ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/jolokia/JolokiaProperties.{sc-ext}[JolokiaProperties])
management.endpoint.jolokia.config.*= # Jolokia settings. See the Jolokia manual for details.
management.endpoint.jolokia.enabled=true # Whether to enable Jolokia.
# HEALTH INDICATORS # HEALTH INDICATORS
management.health.db.enabled=true # Whether to enable database health check. management.health.db.enabled=true # Whether to enable database health check.
management.health.cassandra.enabled=true # Whether to enable Cassandra health check. management.health.cassandra.enabled=true # Whether to enable Cassandra health check.
@ -1288,11 +1292,6 @@ content into your application. Rather, pick only the properties that you need.
management.info.git.enabled=true # Whether to enable git info. management.info.git.enabled=true # Whether to enable git info.
management.info.git.mode=simple # Mode to use to expose git information. management.info.git.mode=simple # Mode to use to expose git information.
# JOLOKIA ({sc-spring-boot-actuator-autoconfigure}/jolokia/JolokiaProperties.{sc-ext}[JolokiaProperties])
management.jolokia.config.*= # Jolokia settings. See the Jolokia manual for details.
management.jolokia.enabled=false # Whether to enable Jolokia.
management.jolokia.path=/jolokia # Path at which Jolokia is available.
# METRICS # METRICS
management.metrics.binders.jvm.enabled=true # Whether to enable JVM metrics. management.metrics.binders.jvm.enabled=true # Whether to enable JVM metrics.
management.metrics.binders.logback.enabled=true # Whether to enable Logback metrics. management.metrics.binders.logback.enabled=true # Whether to enable Logback metrics.

View File

@ -136,8 +136,13 @@ content.
|`prometheus` |`prometheus`
|Exposes metrics in a format that can be scraped by a Prometheus server. |Exposes metrics in a format that can be scraped by a Prometheus server.
|`jolokia`
|Exposes JMX beans over HTTP (when Jolokia is on the classpath, not availble for WebFlux).
|=== |===
To learn more about the Actuator's endpoints and their request and response formats, To learn more about the Actuator's endpoints and their request and response formats,
please refer to the separate API documentation ({spring-boot-actuator-api}/html[HTML] or please refer to the separate API documentation ({spring-boot-actuator-api}/html[HTML] or
{spring-boot-actuator-api}/pdf/spring-boot-actuator-web-api.pdf[PDF]). {spring-boot-actuator-api}/pdf/spring-boot-actuator-web-api.pdf[PDF]).
@ -857,8 +862,9 @@ Maven, you would add the following dependency:
</dependency> </dependency>
---- ----
Jolokia can then be accessed by using `/actuator/jolokia` on your management HTTP The Jolokia endpoint can then be exposed by adding `jolokia` or `*` to the
server. `management.endpoints.web.expose` property. You can then be accessed it by using
`/actuator/jolokia` on your management HTTP server.
@ -866,11 +872,12 @@ server.
==== Customizing Jolokia ==== Customizing Jolokia
Jolokia has a number of settings that you would traditionally configure by setting servlet Jolokia has a number of settings that you would traditionally configure by setting servlet
parameters. With Spring Boot, you can use your `application.properties` file. To do so, parameters. With Spring Boot, you can use your `application.properties` file. To do so,
prefix the parameter with `management.jolokia.config.`, as shown in the following example: prefix the parameter with `management.endpont.jolokia.config.`, as shown in the following
example:
[source,properties,indent=0] [source,properties,indent=0]
---- ----
management.jolokia.config.debug=true management.endpoint.jolokia.config.debug=true
---- ----
@ -878,7 +885,7 @@ prefix the parameter with `management.jolokia.config.`, as shown in the followin
[[production-ready-disabling-jolokia]] [[production-ready-disabling-jolokia]]
==== Disabling Jolokia ==== Disabling Jolokia
If you use Jolokia but do not want Spring Boot to configure it, set the If you use Jolokia but do not want Spring Boot to configure it, set the
`management.jolokia.enabled` property to `false`, as follows: `management.endpoint.jolokia.enabled` property to `false`, as follows:
[source,properties,indent=0] [source,properties,indent=0]
---- ----

View File

@ -2,4 +2,3 @@ spring.security.user.name=user
spring.security.user.password=password spring.security.user.password=password
management.health.diskspace.enabled=false management.health.diskspace.enabled=false
management.endpoints.web.expose=* management.endpoints.web.expose=*
management.jolokia.enabled=true