mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
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:
parent
f8cdc01474
commit
017efda6ec
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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.ParameterValueMapper;
|
||||
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.PathMappedEndpoints;
|
||||
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.ControllerEndpointsSupplier;
|
||||
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.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
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.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -138,4 +142,20 @@ public class WebEndpointAutoConfiguration {
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
* 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
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "management.jolokia")
|
||||
@ConfigurationProperties(prefix = "management.endpoint.jolokia")
|
||||
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
|
||||
* the documentation of Jolokia for more details.
|
||||
*/
|
||||
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() {
|
||||
return this.config;
|
||||
}
|
||||
|
@ -795,7 +795,7 @@
|
||||
"type": "java.lang.String",
|
||||
"description": "Endpoint URL path.",
|
||||
"deprecation": {
|
||||
"reason": "Endpoint path is no longer customizable.",
|
||||
"replacement": "management.endpoints.web.path-mapping.jolokia",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
@ -1734,4 +1734,3 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfigura
|
||||
org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration,\
|
||||
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.liquibase.LiquibaseEndpointAutoConfiguration,\
|
||||
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.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.servlet.WebMvcEndpointManagementContextConfiguration,\
|
||||
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.reactive.ReactiveManagementChildContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementChildContextConfiguration,\
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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.PathMapper;
|
||||
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.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -35,12 +37,15 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Yunkun Huang
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class WebEndpointAutoConfigurationTests {
|
||||
|
||||
private static final AutoConfigurations CONFIGURATIONS = AutoConfigurations
|
||||
.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class);
|
||||
|
||||
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(EndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class));
|
||||
.withConfiguration(CONFIGURATIONS);
|
||||
|
||||
@Test
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
* 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.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.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.servlet.ServletManagementContextAutoConfiguration;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link JolokiaManagementContextConfiguration}.
|
||||
* Integration tests for {@link JolokiaEndpoint}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
@TestPropertySource(properties = "management.jolokia.enabled=true")
|
||||
@TestPropertySource(properties = "management.endpoints.web.expose=jolokia")
|
||||
public class JolokiaManagementContextConfigurationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
@ -70,7 +72,7 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
|
||||
public void jolokiaIsExposed() {
|
||||
ResponseEntity<String> response = this.restTemplate
|
||||
.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("\"request\":{\"type\"");
|
||||
}
|
||||
@ -79,7 +81,7 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
|
||||
public void search() {
|
||||
ResponseEntity<String> response = this.restTemplate
|
||||
.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");
|
||||
}
|
||||
|
||||
@ -87,7 +89,7 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
|
||||
public void read() {
|
||||
ResponseEntity<String> response = this.restTemplate.getForEntity(
|
||||
"/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");
|
||||
}
|
||||
|
||||
@ -95,18 +97,19 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
|
||||
public void list() {
|
||||
ResponseEntity<String> response = this.restTemplate.getForEntity(
|
||||
"/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");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@MinimalWebConfiguration
|
||||
@Import({ JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
JolokiaEndpointAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class })
|
||||
ServletEndpointManagementContextConfiguration.class })
|
||||
protected static class Application {
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -291,6 +291,9 @@ public abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O exten
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isFilterMatch(Class<?> filter, EndpointBean endpointBean) {
|
||||
if (!isEndpointExposed(endpointBean.getBean())) {
|
||||
return false;
|
||||
}
|
||||
if (filter == null) {
|
||||
return true;
|
||||
}
|
||||
|
@ -25,6 +25,11 @@ package org.springframework.boot.actuate.endpoint.invoke;
|
||||
@FunctionalInterface
|
||||
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}.
|
||||
* @param parameter the parameter to map
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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.EndpointDiscoverer;
|
||||
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.web.PathMapper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@ -54,7 +52,7 @@ public class ControllerEndpointDiscoverer
|
||||
public ControllerEndpointDiscoverer(ApplicationContext applicationContext,
|
||||
PathMapper endpointPathMapper,
|
||||
Collection<EndpointFilter<ExposableControllerEndpoint>> filters) {
|
||||
super(applicationContext, new NoOpParameterValueMapper(), Collections.emptyList(),
|
||||
super(applicationContext, ParameterValueMapper.NONE, Collections.emptyList(),
|
||||
filters);
|
||||
Assert.notNull(endpointPathMapper, "EndpointPathMapper must not be null");
|
||||
this.endpointPathMapper = endpointPathMapper;
|
||||
@ -88,17 +86,4 @@ public class ControllerEndpointDiscoverer
|
||||
"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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,13 +18,12 @@ package org.springframework.boot.actuate.endpoint.web.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Operation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;
|
||||
|
||||
/**
|
||||
* A discovered {@link ExposableEndpoint controller endpoint}.
|
||||
* A discovered {@link ExposableControllerEndpoint controller endpoint}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<EndpointServlet>}
|
||||
* 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;
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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> {
|
||||
|
||||
}
|
@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ 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.PathMapper;
|
||||
@ -61,6 +62,7 @@ public class ControllerEndpointDiscovererTests {
|
||||
assertThat(endpoint.getId()).isEqualTo("testcontroller");
|
||||
assertThat(endpoint.getController())
|
||||
.isInstanceOf(TestControllerEndpoint.class);
|
||||
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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.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
|
||||
management.health.db.enabled=true # Whether to enable database 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.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
|
||||
management.metrics.binders.jvm.enabled=true # Whether to enable JVM metrics.
|
||||
management.metrics.binders.logback.enabled=true # Whether to enable Logback metrics.
|
||||
|
@ -136,8 +136,13 @@ content.
|
||||
|`prometheus`
|
||||
|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,
|
||||
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]).
|
||||
@ -857,8 +862,9 @@ Maven, you would add the following dependency:
|
||||
</dependency>
|
||||
----
|
||||
|
||||
Jolokia can then be accessed by using `/actuator/jolokia` on your management HTTP
|
||||
server.
|
||||
The Jolokia endpoint can then be exposed by adding `jolokia` or `*` to the
|
||||
`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
|
||||
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,
|
||||
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]
|
||||
----
|
||||
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]]
|
||||
==== Disabling Jolokia
|
||||
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]
|
||||
----
|
||||
|
@ -2,4 +2,3 @@ spring.security.user.name=user
|
||||
spring.security.user.password=password
|
||||
management.health.diskspace.enabled=false
|
||||
management.endpoints.web.expose=*
|
||||
management.jolokia.enabled=true
|
||||
|
Loading…
Reference in New Issue
Block a user