Separate scalabilty concerns from services - spring-boot

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;

Related

Spring tests shutting down standalone wiremock server

I have some end-to-end UI tests with WebDriver that use a remote wiremock instance, that I connect to in the following way:
#Configuration
public class WireMockConfiguration {
#Bean
public WireMock wireMock() {
return new WireMock("my-pyroxy.corp", 8080);
}
}
I have noticed that after tests finish, the wiremock server receives a shutdown request. The Wiremock::shutdown method is not marked with any annotation like #PreDestroy but Spring is still invoking it.
How do I stop it (apart from creating this wiremock client bean outside of the spring context?)
From the documentation of #Bean, I have learned this
To disable destroy method inference for a particular #Bean, specify an empty string as the value, e.g. #Bean(destroyMethod="")

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!

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

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.

Spring Bean Container

I wanted to write test cased for testing my service using springjunit runner.
My service will call another service and transform its out put and send the response.
I thouhgt that server need to be up and running for calling the other service while running junit.
But I was told that spring junit doesnt need server to be running.
Spring container will do the magic it seems.
Am not pretty sure how this happens.
Can any one enlighten me with how spring container can act as server?
If its so silly quesiton,sorry for that.Thanks in advance
do you need server to run java.class , answer is no, untill unless if you have any ejb component to be called from your service, or you service need some external web service to
respond (here you may need to either mock this service to give mock data or run the service on server)
i have service which calls data access layer , sometimes service calls another service.
all you need to have spring context configuration in your test class
#ContextConfiguration({ "classpath:spring-context.xml", "classpath:otherservice-context.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
#Component
public class TestJuint{
#Autowire
private otherService otherServiceImpl;
#Autowire
private service serviceImpl;
#Test
public void testDummy{
serviceImpl.addDummy(dummyObj);
}
}
suppose if you need to have another service from some other package then you might want to include its context file in context configuration, so that its bean reference will be in spring context while autowiring

Resources