Expose context hierarchy in beans endpoint

Previously, the beans endpoint would only expose the context that
contained the endpoint. This commit updates the endpoint so that
the context that contains the endpoint and all of its ancestors are
exposed.

In a context hierarhcy, the relation ship is child -> parent and there
is no way to navigate from a parent to a child. As a result, any
contexts that are descendants of the context containing the endpoint
are not exposed.

Closes gh-5188
This commit is contained in:
Andy Wilkinson
2017-01-16 11:44:20 +00:00
parent dbee44a6b5
commit a72365e1a2
2 changed files with 179 additions and 4 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* 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.
@@ -16,7 +16,9 @@
package org.springframework.boot.actuate.endpoint;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -24,22 +26,25 @@ import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.LiveBeansView;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
/**
* 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
* behavior of LiveBeansView). Otherwise only the current application context.
* behavior of LiveBeansView). Otherwise only the current application context hierarchy.
*
* @author Dave Syer
* @author Andy Wilkinson
*/
@ConfigurationProperties(prefix = "endpoints.beans")
public class BeansEndpoint extends AbstractEndpoint<List<Object>>
implements ApplicationContextAware {
private final LiveBeansView liveBeansView = new LiveBeansView();
private final HierarchyAwareLiveBeansView liveBeansView = new HierarchyAwareLiveBeansView();
private final JsonParser parser = JsonParserFactory.getJsonParser();
@@ -51,7 +56,7 @@ public class BeansEndpoint extends AbstractEndpoint<List<Object>>
public void setApplicationContext(ApplicationContext context) throws BeansException {
if (context.getEnvironment()
.getProperty(LiveBeansView.MBEAN_DOMAIN_PROPERTY_NAME) == null) {
this.liveBeansView.setApplicationContext(context);
this.liveBeansView.setLeafContext(context);
}
}
@@ -60,4 +65,37 @@ public class BeansEndpoint extends AbstractEndpoint<List<Object>>
return this.parser.parseList(this.liveBeansView.getSnapshotAsJson());
}
private static class HierarchyAwareLiveBeansView extends LiveBeansView {
private ConfigurableApplicationContext leafContext;
private void setLeafContext(ApplicationContext leafContext) {
this.leafContext = asConfigurableContext(leafContext);
}
@Override
public String getSnapshotAsJson() {
return generateJson(getContextHierarchy());
}
private ConfigurableApplicationContext asConfigurableContext(
ApplicationContext applicationContext) {
Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext,
"'" + applicationContext
+ "' does not implement ConfigurableApplicationContext");
return (ConfigurableApplicationContext) applicationContext;
}
private Set<ConfigurableApplicationContext> getContextHierarchy() {
Set<ConfigurableApplicationContext> contexts = new LinkedHashSet<ConfigurableApplicationContext>();
ApplicationContext context = this.leafContext;
while (context != null) {
contexts.add(asConfigurableContext(context));
context = context.getParent();
}
return contexts;
}
}
}