[spring-projects/spring-boot]执行器端点的写操作不适用于 bean 类

2024-04-23 135 views
2

Spring Boot版本:2.0.3.RELEASE

使用的 Spring Boot 示例可以在“端点基础设施”部分@WriteOperation找到。 这个示例工作正常,因为 JSON 主体作为带有字符串值的参数传递:并且 LogLevel 是一个枚举。{ "configuredLevel": "WARN" }

不幸的是,如果您尝试传递 HTTP POST 请求正文中包含的 bean 类,那么它将失败并返回 400 - 错误请求。您可以看一下这个不起作用的示例: http://www.baeldung.com/spring-boot-actuators,4.7。 “创建自定义端点”部分

使用curl命令:

$ curl -X POST http://localhost:8080/actuator/features/payment -H "Content-Type: application/json" -d '{"enabled":  true}'
response: 
{"timestamp":"2018-07-23T09:57:57.922+0000","status":400,"error":"Bad Request","message":"Missing parameters: feature","path":"/actuator/features/payment"}

它表示缺少特征参数。即使添加了这个功能参数:

$ curl -X POST http://localhost:8080/actuator/features/payment -H "Content-Type: application/json" -d '{"feature": {"enabled":true}}'
response:
"Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of java.lang.String out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException"
Feature bean class is not interpreted because Jackson is expecting a string instead of a bean class.

在调试 Jackson 和 Spring 源代码后,我发现问题出现在启动时,因为RequestMappingHandlerMapping.isHandler()知道创建处理程序用于仅从端点方法识别 bean 类ControllerRequestMapping。根据50.8“实现自定义端点”部分,端点和 WebEndpoint 通过 HTTP 公开。因此,这两个类都应该添加到isHandler()方法中以创建用于解析 bean 类的处理程序。

回答

2

您能否分享您一直在使用的显示错误的示例项目?我想知道您是否不小心将@Controller或添加@RestController到您的端点>

RequestMappingHandlerMapping.isHandler()执行器代码不使用该方法。org.springframework.boot.actuate.endpoint.web.servlet.ControllerEndpointHandlerMapping详情请参阅班级。

1

没有意外的 Controller 或 RestController 注释。 RequestMappingHandlerMapping 不是一个抽象类,因此在我们的例子中它是实例化的,不需要 ControllerEndpointHandlerMapping

您可以在下面找到堆栈跟踪: 自定义端点开始堆栈跟踪

4

@DanielLupu 谢谢你,但这不是我们想要的。请分享一个我们可以克隆/下载并自行运行的示例。

2

感谢您提供样品。这正如广告中所宣传的那样工作:

  1. 当您使用端点抽象时,我们希望确保可以通过 JMX 调用此类端点。声明这种类型将不允许
  2. 看起来您希望将 JSON 主体序列化回Feature.如果添加第三个参数会发生什么?

如果您想最终获得此类更高级别的方法签名,我不确定@Endpoint是否适合您(考虑 JMX 用例)。

4

如果您只想支持 Spring MVC,您可能需要查看注释@ControllerEndpoint,它允许您使用标准 MVC 注释进行开发,但会牺牲可移植性。

3

如果这些参数是字符串,您可以添加任意数量的参数。您能否向我指出其中描述了所有这些行为的文档?在我看来,应该更新文档,并提供有关输入参数和端点接口约束的清晰解释。

8

如果这些参数是字符串,您可以添加任意数量的参数。

我并不是真的在问问题,这当然不是我们会考虑的问题(首先,还有其他类型需要考虑,但这并不能以任何方式解决 JMX 问题)。

文档在这里。我同意我们可以使用一个例子(以及一些关于以技术不可知的方式公开操作意味着什么的谨慎注释)。也许您愿意贡献 PR 来改进文档?

7

如果时间允许,我想为 Spring 文档做出贡献。目前我发现以下内容:

  1. 端点注释和用 Endpoint 注释的其他端点也必须注释,@Component以便在执行器中公开它下面的示例应该更新: https://spring.io/blog/2017/08/22/introducing-actuator-endpoints -in-spring-boot-2-0
  2. 没有 的注释WebEndpointExtension,因此 https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#product-ready-endpoints-custom-input 50.8.2 自定义 Web 端点“在@Endpoint@WebEndpoint,或者@WebEndpointExtension使用 Jersey、Spring MVC 或 Spring WebFlux 通过 HTTP 自动公开”应该更新,最有可能的是EndpointWebExtension
  3. 绝对是一个命名约定问题:ServletEndpoint以及EndpointServlet 50.8.3 Servlet 端点“Servlet 可以通过实现一个@ServletEndpoint也实现了注释的类来公开为端点Supplier<EndpointServlet>。”
  4. 50.8.3 Servlet 端点和 50.8.4 控制器端点部分的结尾是:“..但以牺牲可移植性为代价。只要有可能,应首选@Endpoint和注释。”@WebEndpoint我认为它在可移植性方面与 JMX 相关(如果您考虑到其他可移植性,请纠正我),因为我只发现 和 的这个@Endpoint优点@WebEndpoint。在我看来,这些甚至不是 HTTP 端点,因为处理输入参数的 JMX 约定有限,我们无法利用 REST 和 SOAP。因此,这些是有限的端点,并且没有公开 java servlet 应该做什么:“Java servlet 是扩展服务器功能的 Java 软件组件。尽管 servlet 可以响应任何类型的请求”我知道您不能接受现在考虑这一点,但也许在下一个 Spring Boot 版本中,当涉及到添加功能时,您会考虑以重用现有控制器注释的方式进行改进(我可以帮助您)。仅针对执行器和 JMX 支持添加了超过 5 个注释,这些注释可以以简单的方式实现,以仅从应用程序属性启用必要的支持(或最终在RestController或 的方法上添加注释Controller)。如果这个问题得到解决,那么添加自定义端点将以自然的方式执行,从而为监控 API 端点带来直接优势。

我不想让你在没有解释的情况下:

看起来您希望将 JSON 正文序列化回功能。如果添加第三个参数会发生什么?最初我尝试将它与 actuate 操作符结合使用@RequestBody,但失败了。我没想到会有两种单独的方法来处理端点。

我能够测试RestControllerEndpointControllerEndpoint但没有机会ServletEndpoint。它在 spring-boot 启动时像这样注册:“Registered '/actuator/servlet-features' to servlet-features-actuator-endpoint”,但没有像 RestControllerEndpoint 这样的 HTTP 可用方法可以调用:“Mapped”{[/actuator/rest -features/{id}],methods=[GET]}" 到 public org.springframework.http.ResponseEntity com.example.web.simpleweb.actuator.FeatureRestControllerEndpoint.getPayment(java.lang.String)" 我应该如何称呼它从客户端?

0

如果时间允许,我想为 Spring 文档做出贡献。目前我发现以下内容:

感谢您的反馈,但我们不会将问题跟踪器用作“支持论坛”。我们希望问题仅集中在一个主题上。这是关于您无法从 json 数据注入 POJO 的事实。正如我所指出的,如有必要,我很乐意审查 PR 或其他问题。

作为记录,我不同意该博客文章摘录应添加@Component(请查看配置部分)。我还修正了 2 中提出的拼写错误,谢谢。

3

我为列表中的第二名提出了#13894。谢谢!

3

我认为它在可移植性方面与 JMX 有关(如果您考虑其他可移植性,请纠正我)

就可移植性而言,我们目前指的是 JMX 和 HTTP,但将来我们总是可以支持更多技术。 HTTP 不仅限于 servlet,我们还支持 WebFlux(它不使用 servlet API)。

也许在下一个 Spring Boot 版本中,您会考虑以重用现有控制器注释的方式进行改进

我们有意为执行器端点创建了更高级别的抽象。尝试伪造 MVC 注释来做一些不同的事情确实效果不太好。我们还需要考虑这样一个事实:我们不希望执行器端点被发现并暴露为常规 Spring MVC 控制器(这就是我们故意不使用@RestControlleror 的原因@Controller。简而言之,我们不太可能很快改变我们当前的方法。

8

我已经打开#13896,看看我们是否可以改进有关支持的参数类型的文档。

9

有道理,我的意图不是偏离最初的问题,但我在试图解决一件事的当前文档中遇到了太多问题。例如,您刚刚帮助我完成了配置部分,但可能您没有注意到这些配置参数已被弃用:endpoints.loggers.enabled=true,endpoints.loggers.* 无论如何,我试图指出除了@之外您还需要其他东西端点注释(@Bean 或 @Component)用于在执行器上下文路径中公开端点,我认为将来也可以简化。我还发现了 Endpoint bean 加载的其他问题,但我将单独解决这些问题。我了解了写操作的限制,所以这个问题可以关闭了。

2

我确实知道这一点。博客是一个有生命的东西,我不确定我们是否应该总是返回并更改内容(自从撰写本文以来,执行器已经发生了显着变化)。希望接下来会发生什么?应该给你一个提示。请参阅文档,如果博客文章中的某些内容在文档中得到解释和缺失,我们很乐意审核 PR。

我认为将来也可以简化。

我可以理解这一点,但如果您在满足特定条件时启用端点,那么在我看来扫描它没有多大意义。同样,这就是配置部分试图展示的内容。

我了解写入操作的限制,因此可以关闭此问题。

根据记录,我不认为这是一个限制,而是一个有意识的选择,允许其他客户端调用该操作(如本问题上下文中所述)。