[spring-projects/spring-boot]确定端点 bean 时跳过范围目标

2024-04-20 595 views
4

你好,这是一个first-timers-only问题。这意味着我们一直在努力让那些以前没有为我们的代码库做出过贡献的人,甚至以前没有为开源做出过贡献的人更容易理解。

如果您就是这样,我们有兴趣帮助您迈出第一步,并可以回答您的问题并为您提供帮助。请注意,我们对自由和开源软件中代表性不足的群体的贡献特别感兴趣!

如果您以前曾贡献过,请考虑将这一贡献留给新人,并查看我们的一般ideal-for-contribution问题。谢谢!

背景

@Endpoint注释将类型标识为执行器端点。 Spring Boot 的执行器基础结构会查找具有此注释的 bean。

问题

当 Spring Cloud@RefreshScope在一个 bean 上使用时@Endpoint,它会为该端点注册另一个 bean,其 bean 名称以 为前缀scopedTarget。 Spring Boot 在查找@Endpointbean 时也会发现此 bean,但会失败,因为它找到两个具有相同 ID 的端点 bean。

解决方案

我们应该像这次提交中针对不同类型的 bean 所做的那样,过滤掉scopedTarget.端点 bean 的版本。ScopedProxyUtils.isScopedTarget(name)

可以在此处找到用于发现端点 bean 的代码。

测试可以为同一@Endpoint类注册两个 bean,其中一个名称前缀为 ,scopedTarget.并断言仅@Endpoint发现原始 bean。

回答

4

我想从事这方面的工作,请。

3

@vpondala 酷!如果您有任何问题,请随时提出。我们期待您的拉取请求。

0

第一次尝试这个问题。

7

谢谢@jbresesti,但是@vpondala 已经声明了这个问题。请留意另一个仅限新手的问题,我们很乐意指导您完成整个过程。

6

我可以按照这个过程以任何方式学习吗?如何?谢谢。

4

本期的描述中描述了该过程,其中包含有关设置 Boot 存储库的本地副本以及将代码导入 IDE 的信息的链接。

为了避免让这个问题进一步脱离主题,请在 Gitter 上跟进任何进一步的问题。

3

你在@vpondala 上怎么样?如果有什么我们可以帮忙的,请随时询问。

2

对于延迟在这里@wilkinsona 表示歉意。我将在一天左右提交 PR。

8

@wilkinsona @mbhave 我真诚的道歉。我目前无法处理此问题。请将其重新分配给任何有兴趣贡献的其他人。再次道歉。

3

我可以解决这个问题吗?

3

另外,是否有一个示例项目可以用来重现错误并对其进行测试?

1

我想从事这个工作,请

7

按照评论顺序,@jbresesti 首先表示感兴趣。

@jbresesti 如果您仍然有兴趣解决这个问题,请告诉我们。如果没有,我们可以让@rahul404 认领它。

7

你好,我现在可以索赔这个问题吗?

1

@rahul404 都是你的了。谢谢。如果您需要我们,我们将随时回答您在进行更改时遇到的任何问题。

5

您好,是否有一个代码片段可以用来重现该错误。

3

上面 @mbhave 的描述中有一些关于如何重现问题的详细信息:

为同一个注册两个bean @Endpoint class,其中一个的名称前缀为scopedTarget.

这看起来像这样:

@Configuration
static class ScopedTargetEndpointConfiguration {

    @Bean
    public TestEndpoint testEndpoint() {
        return new TestEndpoint();
    }

    @Bean(name = "scopedTarget.testEndpoint")
    public TestEndpoint scopedTargetTestEndpoint() {
        return new TestEndpoint();
    }

}

我将添加一个像这样的配置类EndpointDiscovererTests,然后添加一个加载测试ScopedTargetEndpointConfigurationTestEndpointDiscoverer使用加载的上下文创建一个测试,调用getEndpoints()并断言仅返回一个端点。

在对此进行任何更改之前,EndpointDiscoverer此测试将失败,因为由于发现了getEndpoints()两个 bean,因此将引发异常。TestEndpoint

8

好的,我知道了。也许我误解了指示,我执行了以下操作来重现该问题

@Configuration
@ImportAutoConfiguration(RefreshAutoConfiguration.class)
    static class RefreshEndpointClashingConfiguration{
        @Bean
        @RefreshScope
        public RefreshScopeTestEndpoint refreshScopeTestEndpoint() {
            return new RefreshScopeTestEndpoint();
        }
    }

@Endpoint(id = "refreshTest")
    static class RefreshScopeTestEndpoint{

    }

我将使用你的代码片段。但只是为了确认一下,我的代码是否是一种不正确的复制方式?

9

不,这是重现它的好方法,也是导致最初报告的问题的原因。建议使用上面的代码片段是因为它@RefreshScope是 Spring Cloud 的一部分。 Spring Cloud 依赖于 Spring Boot,因此即使在测试中,我们也不能在 Spring Boot 中依赖它,因为这样做会在两个项目之间创建循环依赖关系。

在幕后,@RefreshScope会创建一个额外的 bean,并将其scopedTarget.添加到原始 bean 的名称中。ScopedTargetEndpointConfiguration正在模拟@RefreshScope所做的事情,以便我们可以在不依赖 Spring Cloud 的情况下重现问题。

9

我已经解决了这个问题,但我陷入了其中一个测试用例。以下是我写的测试用例。

@Test
public void getEndpointsWhenEndpointsArePrefixedWithScopedTargetShouldRegisterOnlyOneEndpoint() {
        load(ScopedTargetEndpointConfiguration.class, (
                context) -> {
            Collection<TestExposableEndpoint> collection =
                    new TestEndpointDiscoverer(context).getEndpoints();
            assertThat(collection).hasSize(1);
            TestExposableEndpoint endpoint = collection.iterator().next();
        });
    }

我想包括一个测试用例,如下所示:

assertThat(beanName).doesNotStartWith("scopedTarget");

但是 collection.iterator().next().getEndpointBean() 返回 Object 类型的对象

有没有办法获得豆子名字?

2

@rahul404 正如您所注意到的,发现者提供对 bean 本身的访问,而不是对 bean 定义的访问。这是检查名称所需的定义,但它并不容易获得。

我明白为什么验证 bean 的名称会很好,因为它允许您检查是否scopedTarget.testEndpoint已被过滤掉而不是testEndpoint.您可以通过检查端点 bean 是否与testEndpoint()方法返回的内容相同来做到这一点ScopedTargetEndpointConfiguration。像这样的东西:

assertThat(endpoints.iterator().next().getEndpointBean()).isSameAs(context
        .getBean(ScopedTargetEndpointConfiguration.class).testEndpoint());
0

非常感谢 @rahul404 的公关。我将结束这一活动以支持它。

4

谢谢。你帮了很大的忙。我期待做出更多贡献。