diff --git a/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/autoconfigure/BeansConfiguration.java b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/autoconfigure/BeansConfiguration.java new file mode 100644 index 00000000000..295c416b024 --- /dev/null +++ b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/autoconfigure/BeansConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2013 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.bootstrap.actuate.autoconfigure; + +import javax.servlet.Servlet; + +import org.springframework.bootstrap.actuate.endpoint.beans.BeansEndpoint; +import org.springframework.bootstrap.context.annotation.ConditionalOnClass; +import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean; +import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.DispatcherServlet; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for /beans endpoint. + * + * @author Dave Syer + */ +@Configuration +@ConditionalOnClass({ Servlet.class, DispatcherServlet.class }) +@ConditionalOnMissingBean({ BeansEndpoint.class }) +public class BeansConfiguration { + + @Bean + public BeansEndpoint beansEndpoint() { + return new BeansEndpoint(); + } + +} diff --git a/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/autoconfigure/ManagementEndpointsRegistration.java b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/autoconfigure/ManagementEndpointsRegistration.java index 72b7452858e..63af890d7db 100644 --- a/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/autoconfigure/ManagementEndpointsRegistration.java +++ b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/autoconfigure/ManagementEndpointsRegistration.java @@ -28,7 +28,7 @@ import org.springframework.context.annotation.Import; @Configuration @ConditionalOnManagementContext @Import({ MetricsConfiguration.class, HealthConfiguration.class, - ShutdownConfiguration.class, TraceConfiguration.class }) + ShutdownConfiguration.class, TraceConfiguration.class, BeansConfiguration.class }) public class ManagementEndpointsRegistration { } \ No newline at end of file diff --git a/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/endpoint/beans/BeansEndpoint.java b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/endpoint/beans/BeansEndpoint.java new file mode 100644 index 00000000000..1a57981a449 --- /dev/null +++ b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/endpoint/beans/BeansEndpoint.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2013 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.bootstrap.actuate.endpoint.beans; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.support.LiveBeansView; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * Exposes JSON view of Spring beans. If the {@link Environment} contains a key setting + * the {@link LiveBeansView#MBEAN_DOMAIN_PROPERTY_NAME} then all application contexts in + * the JVM will be shown (and the corresponding MBeans will be registered per the standard + * behaviour of LiveBeansView). Otherwise only the current application context. + * + * @author Dave Syer + */ +@Controller +public class BeansEndpoint implements ApplicationContextAware { + + private LiveBeansView liveBeansView = new LiveBeansView(); + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + if (context.getEnvironment() + .getProperty(LiveBeansView.MBEAN_DOMAIN_PROPERTY_NAME) == null) { + this.liveBeansView.setApplicationContext(context); + } + } + + @RequestMapping(value = "${endpoints.beans.path:/beans}", produces = "application/json") + @ResponseBody + public String error(HttpServletRequest request) { + return this.liveBeansView.getSnapshotAsJson(); + } +} diff --git a/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/properties/EndpointsProperties.java b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/properties/EndpointsProperties.java index 7ad3a82355b..2dd786a9d53 100644 --- a/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/properties/EndpointsProperties.java +++ b/spring-bootstrap-actuator/src/main/java/org/springframework/bootstrap/actuate/properties/EndpointsProperties.java @@ -51,6 +51,9 @@ public class EndpointsProperties { @Valid private Endpoint dump = new Endpoint("/dump"); + @Valid + private Endpoint beans = new Endpoint("/beans"); + public Endpoint getInfo() { return this.info; } @@ -79,6 +82,10 @@ public class EndpointsProperties { return this.dump; } + public Endpoint getBeans() { + return this.beans; + } + public static class Endpoint { @NotNull diff --git a/spring-bootstrap-samples/spring-bootstrap-actuator-sample/src/test/java/org/springframework/bootstrap/sample/test/ServiceBootstrapApplicationTests.java b/spring-bootstrap-samples/spring-bootstrap-actuator-sample/src/test/java/org/springframework/bootstrap/sample/test/ServiceBootstrapApplicationTests.java index 287becfe43f..13d700a548a 100644 --- a/spring-bootstrap-samples/spring-bootstrap-actuator-sample/src/test/java/org/springframework/bootstrap/sample/test/ServiceBootstrapApplicationTests.java +++ b/spring-bootstrap-samples/spring-bootstrap-actuator-sample/src/test/java/org/springframework/bootstrap/sample/test/ServiceBootstrapApplicationTests.java @@ -128,6 +128,19 @@ public class ServiceBootstrapApplicationTests { assertEquals(999, body.get("status")); } + @Test + public void testBeans() throws Exception { + @SuppressWarnings("rawtypes") + ResponseEntity entity = getRestTemplate("user", "password").getForEntity( + "http://localhost:8080/beans", List.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertEquals(1, entity.getBody().size()); + @SuppressWarnings("unchecked") + Map body = (Map) entity.getBody().get(0); + assertTrue("Wrong body: " + body, + ((String) body.get("context")).startsWith("org.springframework")); + } + private RestTemplate getRestTemplate() { return getRestTemplate(null, null); }