Skip to content

Commit 253218b

Browse files
committed
Set classloader for JMX endpoints to application classloader, #12088.
1 parent e0eadfe commit 253218b

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import reactor.core.publisher.Mono;
3333

34+
import org.springframework.beans.factory.BeanClassLoaderAware;
3435
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
3536
import org.springframework.boot.actuate.endpoint.InvocationContext;
3637
import org.springframework.boot.actuate.endpoint.SecurityContext;
@@ -46,11 +47,13 @@
4647
* @author Phillip Webb
4748
* @since 2.0.0
4849
*/
49-
public class EndpointMBean implements DynamicMBean {
50+
public class EndpointMBean implements DynamicMBean, BeanClassLoaderAware {
5051

5152
private static final boolean REACTOR_PRESENT = ClassUtils.isPresent(
5253
"reactor.core.publisher.Mono", EndpointMBean.class.getClassLoader());
5354

55+
private ClassLoader classLoader;
56+
5457
private final JmxOperationResponseMapper responseMapper;
5558

5659
private final ExposableJmxEndpoint endpoint;
@@ -69,6 +72,11 @@ public class EndpointMBean implements DynamicMBean {
6972
this.operations = getOperations(endpoint);
7073
}
7174

75+
@Override
76+
public void setBeanClassLoader(ClassLoader classLoader) {
77+
this.classLoader = classLoader;
78+
}
79+
7280
private Map<String, JmxOperation> getOperations(ExposableJmxEndpoint endpoint) {
7381
Map<String, JmxOperation> operations = new HashMap<>();
7482
endpoint.getOperations()
@@ -90,7 +98,13 @@ public Object invoke(String actionName, Object[] params, String[] signature)
9098
+ "' has no operation named " + actionName;
9199
throw new ReflectionException(new IllegalArgumentException(message), message);
92100
}
93-
return invoke(operation, params);
101+
ClassLoader previousClassLoader = ClassUtils.overrideThreadContextClassLoader(this.classLoader);
102+
try {
103+
return invoke(operation, params);
104+
}
105+
finally {
106+
ClassUtils.overrideThreadContextClassLoader(previousClassLoader);
107+
}
94108
}
95109

96110
private Object invoke(JmxOperation operation, Object[] params)

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.boot.actuate.endpoint.jmx;
1818

19+
import java.net.URL;
20+
import java.net.URLClassLoader;
21+
1922
import javax.management.Attribute;
2023
import javax.management.AttributeList;
2124
import javax.management.AttributeNotFoundException;
@@ -32,6 +35,7 @@
3235
import org.springframework.beans.FatalBeanException;
3336
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
3437
import org.springframework.boot.actuate.endpoint.InvocationContext;
38+
import org.springframework.util.ClassUtils;
3539

3640
import static org.assertj.core.api.Assertions.assertThat;
3741
import static org.hamcrest.CoreMatchers.instanceOf;
@@ -126,6 +130,18 @@ public void invokeWhenActionNameIsNotAnOperationShouldThrowException()
126130
bean.invoke("missingOperation", NO_PARAMS, NO_SIGNATURE);
127131
}
128132

133+
@Test
134+
public void invokeShouldInvokeJmxOperationWithBeanClassLoader()
135+
throws ReflectionException, MBeanException {
136+
TestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(
137+
new TestJmxOperation((arguments) -> ClassUtils.getDefaultClassLoader()));
138+
URLClassLoader beanClassLoader = new URLClassLoader(new URL[]{}, getClass().getClassLoader());
139+
EndpointMBean bean = new EndpointMBean(this.responseMapper, endpoint);
140+
bean.setBeanClassLoader(beanClassLoader);
141+
Object result = bean.invoke("testOperation", NO_PARAMS, NO_SIGNATURE);
142+
assertThat(result).isEqualTo(beanClassLoader);
143+
}
144+
129145
@Test
130146
public void invokeWhenOperationIsInvalidShouldThrowException()
131147
throws MBeanException, ReflectionException {

0 commit comments

Comments
 (0)