Spring Ribbon #LoadBalanced doesn't work with #scope("prototype") for restTemplate - spring

I'm following the official spring ribbon guide, and I noticed one thing.
If a RestTemplate is being created in this way :
#LoadBalanced
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) ---- I added this line
RestTemplate restTemplate(){
logger.warn("create a restTemplate bean..."); --- added this for debug
return new RestTemplate();
}
Then the ribbon client will not be able to find server. (unable to parse client name with server IP address);
I debugged into bean creation process, and noticed that the message, "create a restTemplate bean...", has appeared twice in the log.
And the auto wired restTemplate instance doesn't have a LoadBalancerInterceptor, which is probably why it fails.
So I wonder if there is any suggestion to fix this issue?
P.S: I need RestTemplate to be prototype so that I can set different errorHandlers.

It really fails because of the missing LoadBalancerInterceptor, but the class can be simply injected.
Inject it, and take the #LoadBalanced annotation away:
java
#Bean
#Scope("prototype")
RestTemplate loadBalancedTemplate(LoadBalancerInterceptor loadBalancerInterceptor) {
RestTemplate template = new RestTemplate();
template.getInterceptors().add(loadBalancerInterceptor);
return template;
}

As mentioned by the author:
It turns out that #LoadBalanced annotation won't retrieve a RestTemplate bean from the application context, with 'prototype' scope, it will simply retrieve a new instance, which is not used by any autowired field.

Related

How to get webflux webClient metrics from custom Webclient Builder

I have created a custom Webclient Builder instead of injecting the default builder.
#Configuration
public class WebClientConfig() {
#Bean(name = "myWebClientBuilder")
public Webclient.Builder customBuilder() {
return WebClient.builder();
}
}
I have multiple services where I use this bean myWebClientBuulder and do further customization with chain of ExchangeFilterFunction.
This might not be the recommended way of using the WebClient but I would like to get some insight if there is a way to get the downstream call metrics from the Webclient based on this configuration.
Actuator Endpoint: actuator/metrics/http.client.requests
Spring Boot auto-configured WebClient.Builder is way powerful than customized version.
I tried to configure the custom builder in WebClientConfig() but it started to structure just like a copy version of WebClientAutoConfiguration. I ended up going with the spring boot autoconfigured WebClient.Builder bean.
If it helps, you can study how WebClientAutoConfiguration tries to configure webClient customizers. For metrics, it would be MetricsWebClientCustomizer.

Spring Boot metrics http.client.requests do not work for WebClient reactive applications

I have a spring boot 2.2.2 microservices, which integrations with other services using WebClient (rective). According to Spring documentation, the actuator should return "http.client.requests" metrics by default as Timer is enabled by default. But it does not work for me. I am able to get http.server.requests" metrics.
My WebClient is a bean configured and build with WebClient.builder(), as documented here: https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-metrics-http-clients
Use Spring Boot's preconfigured WebClient.Builder instead of WebClient.builder() to have an instance of WebClient.
You can find more detail here.
As in the following you can have a bean of WebClient.
#Configuration
public class ClientConfiguration {
#Bean
public WebClient webClient(WebClient.Builder webClientBuilder) {
return webClientBuilder
.baseUrl("https://example.org")
.build();
}
}
WebClient.Builder is an Auto-configuration, means the injected point above will receive a newly cloned instance of the builder.
Here is the source for WebClientAutoConfiguration
I've noticed my application has to make a WebClient call before the metrics/http.client.requests endpoint exists. Prior to my application making a WebClient call that endpoint isn't discoverable and returns NOT FOUND.
Hope that helps others in a similar situation!

How does spring work when class is not a spring managed bean but an object referred inside is

I have a RestTemplate Bean in a spring application like this
#Bean
public RestTemplate createRT(HttpClient httpClient) {
return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
}
Note that HttpComponentsClientHttpRequestFactory isn't a spring managed bean.
HttpClient bean is created as follows:
#Bean
public CloseableHttpClient createHttpClient(PoolingHttpClientConnectionManager poolingConnectionManager, RequestConfig rc) throws NoSuchAlgorithmException {
CloseableHttpClient httpClient = HttpClientBuilder
.create()
.setConnectionManager(poolingConnectionManager)
.setDefaultRequestConfig(rc)
.build();
return httpClient;
}
Note that both PoolingHttpClientConnectionManager and RequestConfig are created as spring managed beans.
My question is that in my case, the http client factory object i.e. HttpComponentsClientHttpRequestFactory isn't a spring managed bean but all it's internal objects that it uses to create an HttpClient object for connections are spring managed beans.
So will the HttpClient object that this factory creates going to be a singleton and managed by Spring ? Also would this implementation be considered erroneous in any sense based on the outer object being jvm managed and all inner objects being spring managed ?
I am little confused with it.
There should be no problem with the given snippet with respect to beans lifecycle. You are right that bean HttpComponentsClientHttpRequestFactory will not be Spring managed, but it would still be singleton, because the it is created inside a bean RestTemplate which is singleton. Note that RestTemplate bean would be created with name createRT.
Now coming to the point if it's considered erroneous: Although this is suggested that you should leave the bean and its dependency to be managed by Spring container. But for simple dependencies like in this case, I have seen developers create bean dependencies this way all the time, and everything works just well.
So, if you can, you should make this as a separate bean and let it come as a dependency for bean RestTemplate.

Separate scalabilty concerns from services

I use Spring RestTemplate to consume other services in my local environment.
In production env for scalabilty i want to use a service registry like eureka and ribbon client.
I want to have a clean separation of my code from eureka and ribbon client so that i can run my services locally without the overhead of running a separate service for eureka , registering the services with eureka and also doing a lookup against eureka during orchestration.
I have used spring profile feature to separate out the code and configuration related local and production.
I am stuck at one point where I use RestTemplate to invoke other services.
I want to use the load balanced rest template for prod env and normal rest template for local service call.
I am having difficulty in injecting the type of RestTemplate based on my environment.
Can someone help me with the right way of injecting the RestTemplate so that my services can run locally as well as leverage service registry and ribbon client when running in Prod env without impacting the code.
Thanks,
Sri
Profiles
Use the #Profile annotation on your RestTemplate Bean.
Example:
#Configuration
public class Config {
#Profile("local")
#Bean
public RestTemplate restTemplateLocal(){
return new RestTemplate();
}
#Profile("production")
#LoadBalanced
#Bean
public RestTemplate restTemplateProduction(){
return new RestTemplate();
}
}
Then you can Autowire this bean wherever you need and based on the active Profile, it will return either a normal or LoadBalanced RestTemplate.
#Autowired
private RestTemplate restTemplate;

Spring-Boot 0.5.0.BUILD-SNAPSHOT and customer Json MappingJackson2HttpMessageConverter

Has anyone working with Spring-Boot figured out how to override the default Jackson ObjectMapper that is automatically configured? I have tried to instantiate both the ObjectMapper as a bean and within a MappingJackson2HttpMessageConverter also as a been. But with no success...
Any thoughts?
Spring handles HTTP #ResponseBody using the HttpMessageConverter abstraction, so it's there that you would have to add customizations. Normally you would add a #Bean extending WebMvcConfigurerAdapter and override the configureMessageConverters() method.
Adding a #Bean of type ObjectMapper sounds like a neat way to do this for a Spring Boot application, so you could provide that feature in a pull request if you like.

Resources