diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java index 5bfde9aa9af0..c7b6abd0fa00 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java @@ -30,6 +30,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; +import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.boot.actuate.endpoint.EndpointFilter; @@ -132,11 +133,14 @@ private Collection createEndpointBeans() { this.applicationContext, Endpoint.class); for (String beanName : beanNames) { EndpointBean endpointBean = createEndpointBean(beanName); - EndpointBean previous = byId.putIfAbsent(endpointBean.getId(), endpointBean); - Assert.state(previous == null, - () -> "Found two endpoints with the id '" + endpointBean.getId() - + "': '" + endpointBean.getBeanName() + "' and '" - + previous.getBeanName() + "'"); + if (!ScopedProxyUtils.isScopedTarget(beanName)) { + EndpointBean previous = byId.putIfAbsent(endpointBean.getId(), + endpointBean); + Assert.state(previous == null, + () -> "Found two endpoints with the id '" + endpointBean.getId() + + "': '" + endpointBean.getBeanName() + "' and '" + + previous.getBeanName() + "'"); + } } return byId.values(); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java index a465f180bcbc..3289ea61a073 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java @@ -148,6 +148,17 @@ public void getEndpointsWhenTwoEndpointsHaveTheSameIdShouldThrowException() { "Found two endpoints with the id 'test': ")); } + @Test + public void getEndpointsWhenEndpointsArePrefixedWithScopedTargetShouldRegisterOnlyOneEndpoint() { + load(ScopedTargetEndpointConfiguration.class, (context) -> { + Collection endpoints = new TestEndpointDiscoverer( + context).getEndpoints(); + assertThat(endpoints).hasSize(1); + assertThat(endpoints.iterator().next().getEndpointBean()).isSameAs(context + .getBean(ScopedTargetEndpointConfiguration.class).testEndpoint()); + }); + } + @Test public void getEndpointsWhenTtlSetToZeroShouldNotCacheInvokeCalls() { load(TestEndpointConfiguration.class, (context) -> { @@ -393,6 +404,21 @@ public TestEndpoint testEndpointOne() { } + @Configuration + static class ScopedTargetEndpointConfiguration { + + @Bean + public TestEndpoint testEndpoint() { + return new TestEndpoint(); + } + + @Bean(name = "scopedTarget.testEndpoint") + public TestEndpoint scopedTargetTestEndpoint() { + return new TestEndpoint(); + } + + } + @Import({ TestEndpoint.class, SpecializedTestEndpoint.class, SpecializedExtension.class }) static class SpecializedEndpointsConfiguration {