-
Notifications
You must be signed in to change notification settings - Fork 1.1k
URI Is Being Generated With URI Variables Before RestTemplate Does It #3154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I believe there was the reason to populate variables into URI before calling a So, I would say that flaw is right now is exactly in the Micrometer and it is just not ready for all the use-cases in the field. Fixing this issue for your blindly may lead to breaks in other projects. |
Hi thanks for responding. You have marked this as waiting for reporter but I'm not sure what feedback you are looking for. This is currently causing an issue in our production system because of the amount of timers that are being generated by Micrometer. We have got around this by by setting
but this is not satisfactory as we have basically turned off this feature. Micrometer is the defacto instrumentation library for Spring Boot. It auto instruments RestTemplate and this is it's default behavior. Spring Integration also utilizes RestTemplate for the http outbound gateway, but does so in away that is incompatible with the inbuilt Micrometer library. I've read in the Spring Batch release notes that Micrometer has also been integrated with that project too so is heavily linked with the Spring Eco system. I find it strange that core pieces of Spring (even if they are 3rd party libraries) don't work properly together. We've only recently moved from writing pure Spring boot applications to using Spring Integration. We didn't have any problems with Micrometer instrumentation as we could call RestTemplate.exchange and let it handle the uri variables. With Spring Integration we don't have this choice. It seems a strange decision to let Spring Integration perform this task, when RestTemplate already does it. Perhaps RestTemplate didn't always inject in uri variables, and when it did Spring Integration wasn't upgraded to take advantage of this. You are correct when you say
this is the case today for RestTemplate if somebody decides to build the entire URL themselves, rather than use the URI Template. This is the same for Spring Integration, there is nothing stopping anybody from building up the entire URL instead of the uri-variables. But right now we are building up our URIs in the correct way using a URI Template, but we still can't get it to work. I just looked into the source code for RestTemplate and I can't see the difference between what is happening in Spring Integration and why this functionality can't be left to the RestTemplate to do. They both expand a map of URI variables into the URL template. The only thing I can see that Spring Integration must do is check if uri variables have been defined in the integration flow and call
As it has to generate the correct map of uriVariables from what was defined in the XML. Then it should be able to pass this map to the RestTemplate. |
Right. This is that kind of feedback I'd like to here from reporter. It is really unfortunate that such a Micrometer functionality has not been tested against Spring Integration, but who would guess that we needed it. As I said: there was a reason to supply variables into an URI before I'm afraid that disabling that feature and writing your own Micrometer timer is going to be a right way to overcome the flaw in Micrometer. Of course, you can try to fix the issue here in Spring Integration, if you wish, but I'm afraid it is not going to be so easy. Because again: there was a reason to do that outside of |
Hi, You keep stating that there was a reason why it was done outside of RestTemplate but you haven't said what that is. The only thing that Spring Integration should have to do with the uri variables is identify them and pass this map to RestTemplate. The URLTemplate also works for path parameters e.g.
In the Spring Integration implementation it would be impossible for any metrics library to be able to deal with this by instrumenting the RestTemplate as by the time it reaches Spring Integration has already manipulated the URL to be
We need to be able to instrument different paths as /bookings/{bookingId} is not the same as /bookings/{bookingId}/rooms They might have different implementations with different levels of performance that we'd like to record. How is anybody supposed to instrument this? Is there a plan for Spring Integration to add instrumentation for http outbound gateways? If I was using Spring Boot itself I'd be able to implement this, by calling the appropriate restTemplate.exchange method. It's even documented in the official Spring Boot documentation https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-metrics-http-clients.
In Spring Integration this isn't possible. I've found somebody else's implementation that does as I've suggested. It doesn't look that difficult to implement, nor does it break what people would expect to happen.
|
thank you very much for your feedback! The change I'm talking about was this: #755. Indeed, previously, before Now I see there is a
So, we really can remove a workaround in Spring Integration and fully rely on the I'm not sure that we can still treat this as a bug and try to fix it in the version Does it make sense? Thank you! |
Fixes spring-projects#3154 Spring Framework now provides a `DefaultUriBuilderFactory.EncodingMode` for encoding URIs in the `RestTemplate` before and after uri template enrichment with uri variables. Therefore `encodeUri` and manual uri variables substitution is not necessary in Spring Integration HTTP components * Deprecate `AbstractHttpRequestExecutingMessageHandler.encodeUri` in favor of `DefaultUriBuilderFactory.EncodingMode` and respective configuration on the `RestTemplate` in HTTP module and `WebClient` in WebFlux module
* GH-3154: Support `UriBuilderFactory.EncodingMode` Fixes #3154 Spring Framework now provides a `DefaultUriBuilderFactory.EncodingMode` for encoding URIs in the `RestTemplate` before and after uri template enrichment with uri variables. Therefore `encodeUri` and manual uri variables substitution is not necessary in Spring Integration HTTP components * Deprecate `AbstractHttpRequestExecutingMessageHandler.encodeUri` in favor of `DefaultUriBuilderFactory.EncodingMode` and respective configuration on the `RestTemplate` in HTTP module and `WebClient` in WebFlux module * * Really populate `uriFactory` into an internal `RestTemplate` * Ensure in tests that `encoding-mode` is populated properly into an internal `RestTemplate` * Clean up affected HTTP tests for AssertJ and JUnit 5 * * Clean up formatting * * Apply fix for WebFlux module * Add docs for new `encoding-mode` option * * Remove unused import in the test
spring-integration/spring-integration-http/src/main/java/org/springframework/integration/http/outbound/AbstractHttpRequestExecutingMessageHandler.java
Line 301 in cf01b7c
Spring Integration is generating the entire URI with the declared uri variables, and then passing the generated URI to the RestTemplate exchange method defined in HttpRequestExecutingMessageHandler.exchange()
Here is a truncated declaration of the outbound gateway with the LANGUAGE query parameter templated
This is causing issues in Micrometer which auto instruments the RestTemplate, and is creating a new Timer for every request as the path/query parameters differ. See micrometer-metrics/micrometer#98 for the issue.
From the above we would expect metrics to be recorded like
httpClientRequests{clientName="test",method="GET",status="200",uri="/properties/availability&language={LANGUAGE}",quantile="0.5"}
However what we are seeing is
httpClientRequests{clientName="test",method="GET",status="200",uri="/properties/availability&language=en-US",quantile="0.5"} httpClientRequests{clientName="test",method="GET",status="200",uri="/properties/availability&language=de-DE",quantile="0.5"} httpClientRequests{clientName="test",method="GET",status="200",uri="/properties/availability&language=ko-KR",quantile="0.5"} ........
I believe the correct behavior should be that the URI and the URI variables should be passed to the HttpRequestExecutingMessageHandler.exchange() method, so that RestTemplate can map the variables to the URI. This would correctly create the Micrometer timers for the RestTemplate
The call currently is
`httpResponse = this.restTemplate.exchange(uri, httpMethod, httpRequest,
(ParameterizedTypeReference<?>) expectedResponseType);
`
but it should be
httpResponse = this.restTemplate.exchange(uri, httpMethod, httpRequest, (ParameterizedTypeReference<?>) expectedResponseType, uriVariables);
The text was updated successfully, but these errors were encountered: