spring boot 1.3.3 create multiple resttemplate per env - spring-boot

I am on spring boot 1.3.3 version, I have a requirement where my spring boot application need to call endpoint(s) based on env passed,
which means if env passed as Dev i would need to call devendpoint,
if env passed as Dev1 then need to call dev1endpoint and so on.
So how can I do this ?
Do I need to create multiple restTemplate instances ?
Should I construct the resttemplate dynamically based on env passed ?
As part of constructing resttemplate i would also need to add appllicable interceptor based on env selected.
Plesae suggest.

You can have two beans of the same class. One can be labeled as the primary, and the use on the #Autowired can specify which one to use with the #Qualifier.
Example:
#Configuration
public class MyConfig {
#Bean
#Primary
public RestTemplate typicalConfig() {
// various configs on your rest template
return new RestTemplate();
}
#Bean
public RestTemplate lessTypical() {
// various alternate configurations
return new RestTemplate();
}
}
Now in your service class:
#Service
public class MyService {
#Autowired
RestTemplate typicalRestTemplate;
#Autowired
#Qualifier("lessTypical")
private RestTemplate alternateRestTemplate;
...
}

correct me if I didn't understand your question. I understand that you are going to have different environments but you are going to change this endpoints in runtime depends on some information or whatever, but I don't understand the part when you said you have to create multiple instances of restTemplate for that environments, from my experience on spring boot applications you don't have to do things like that, You just have to create your restTemplate configuration bean.
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
And then injected that object on your services class and do whatever you want with them. I recommend you to read the follow article about restTempalte may this could help you http://www.baeldung.com/rest-template

Related

OpenAPI generator add/generate annotation to ApiClient constructor

I use the newest OpenAPI generator 6.2.1 (https://github.com/OpenAPITools/openapi-generator) to generate an ApiClient with the resttemplate library, which works quite well.
In my application I have now two different RestTemplate beans. So Spring does not know which one to use in the ApiClient constructor.
Parameter 0 of constructor in com.xyz.ApiClient required a single bean, but 2 were found
There is also a hint to solve the problem:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
I don't want to mark one of the beans with #Primary because it is not the primary bean wanted to be used.
I would like to add the #Qualifier to the generated ApiClient constructor like this:
#Autowired
public ApiClient(#Qualifier("myClientProperties") RestTemplate restTemplate) {
this.restTemplate = restTemplate;
init();
}
How can I add the #Qualifier annotation to the generated constructor?
I read lots of openapi generator documentation but did not find anything helpful. There is a solution to add a annotation for models (additionalModelTypeAnnotations in the configOptions of OpenApi configuration).
I expect to generate a #Qualifier annotation to the ApiClient constructor.
You can disable the component scanning for the generated classes. Assuming, your root package is 'my.root.package' and you generate the classes into 'my.root.package.generated', annotate your App / Config class with the following:
#ComponentScan(basePackages = "my.root.package",
excludeFilters = #ComponentScan.Filter(type = FilterType.REGEX,
pattern = "my.root.package.generated.*"))
Then, you can create own (qualified) ApiClients based on your rest templates:
#Bean("rest-template-1")
public RestTemplate restTemplate1() {
return new RestTemplate();
}
#Bean("rest-template-2")
public RestTemplate restTemplate2() {
return new RestTemplate();
}
#Bean("api-client-1")
public ApiClient apiClient1(#Qualifier("rest-template-1") RestTemplate restTemplate) {
return new ApiClient(restTemplate);
}
#Bean("api-client-2")
public ApiClient apiClient2(#Qualifier("rest-template-2") RestTemplate restTemplate) {
return new ApiClient(restTemplate);
}
With those different qualified ApiClients, you init your API classes as you need them.

How to expose endpoints REST lazily?

Scenario:
The Spring Boot application should expose its REST endpoints
only when a specific action occurs.
Is there any way in Spring to lazily expose endpoints, or even the whole HTTP subsystem?
In Apache CXF, we can do something like this:
void exposeEndpoints() {
EndpointImpl endpoint = new EndpointImpl(cxfBus, serviceImpl);
endpoint.publish();
}
How to do the same thing in Spring?
You could take a look at #RefreshScope.
I would define my #RestController beans as follows:
#Configuration
#RefreshScope
public ControllerConfig {
#Bean
#ConditionalOnProperty(value = "should.initialize.rest", havingValue = true)
public SomeController someController(){
....
}
#Bean
#ConditionalOnProperty(value = "should.initialize.rest", havingValue = true)
public SomeOtherController someOtherController(){
....
}
}
and if you start your application with property should.initialize.rest with value false in your application.properties:
should.initialize.rest=false
Then your controllers won't be registered/initialized. When the application is running, you could then update your application.properties to:
should.initialize.rest=true
and make a call to /refresh, then your ApplicationContext will reload/refresh, this time with your REST controllers. You can find more about #RefreshScope below:
https://www.baeldung.com/spring-reloading-properties
https://andressanchezblog.wordpress.com/2016/09/15/refresh-scope-in-spring-cloud/
The solution I have provided below is one of the ways and it may or may not be suitable in your case.
It situation seems like more of design concern rather than particular implementation.
I would suggest you to go with little change in the design.
Store the event in DB or Session (as per requirement) as Boolean.
Create Aspect using AspectJ or Spring's own AOP.
Create Before aspect with specific package pointcuts.
In the #Before advice, check for the boolean flag, if the condition for publishing
satisfies than use joinpoint.proceed() else throw some kind of error saying service not available.
Another way is to create custom Annotation with Aspects. You can use that annotation as per requirement and not on the whole service layer.
The benefit of first approach is that you have the control at generic level and the second approach at service level.
I would suggest to create a new child context with your HTTP subsystem. Something like this:
#Service
public class MyBusinessService {
#Autowired
private final ApplicationContext parentContext;
private AnnotationConfigWebApplicationContext webContext;
public void myBusinessMethod() {
this.webContext = new AnnotationConfigWebApplicationContext();
this.webContext.setParent(parentContext);
this.webContext.scan("com.mybusiness.service.webcomponents");
this.webContext.refresh();
this.webContext.start();
}
}
DISCLAIMER: This is proof-of-concept code, I did not try to compile or run this. But hopefully it is enough to illustrate the concept.

Spring cloud multiple RestTemplate

I am using spring cloud: Spring Boot Application with Eureka + Ribbon default configuration.
I am using 2 RestTemplate configurations, both are #LoadBalanced currently and both of them have the same UriTemplateHandler.
I declared both the #SpringBootApplication and also the #RibbonClient(name="${service.name}") annotations.
My problem is:
When I am trying to access the first configured RestTemplate, the RestTemplate resolvs (by eureka and load balancing by ribbon) to a server , not as I requested as configured in the UriTemplateHandler.
For example: in the UriTemplateHandler I configured "A-Service" and in real time the restTemplate sends the httpRequest to "B-Service"
This behavior happens often, not just for a specific request, but it looks like it only happens when I'm accessing the first configured RestTemplate.
Is it a problem to use 2 RestTemplate with the same uri?
I have no idea why it happens, please advise.
When creating these rest templates as beans, name them uniquely, like e.g.
#LoadBalanced
#Bean("integrationRestTemplate")
public RestTemplate restTemplate() throws Exception {
// build and return your rest template
return ....
}
Then, the other one might be without any specific name e.g.
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
Now, if you have these two distinctive rest templates, you can inject the former one e.g. like that:
#Service
public class MyService {
private final RestTemplate restTemplate;
public ApplicantService(#Qualifier("integrationRestTemplate") RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// service methods
...
}
Basically, the point is you can choose whatever rest template you want, by specifying a #Qualifier.

How to inject RestTemplate

I am not using xml configurations to define beans. Instead using component scanning and autowire to define and inject dependencies.
RestTemplate is part of springframework. How can I inject this class ?
You do it like any other #Bean in a #Configuration class, and inject with #Autowire - However you question suggest that you should read a little more of the Spring documentation.
#Bean
public RestTemplate restTemplate() {
RestTemplate template = new RestTemplate();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(6);
template.setRequestFactory(new HttpComponentsClientHttpRequestFactory(HttpClients.custom().setConnectionManager(connectionManager).build()));
return template;
}
You almost always want to use it together with Apache HttpClient so you get connection pooling. If you need to use it with self-signed https certificates you need a bit more code (let me know if this is the case)

Spring RestTemplate as a Spring Service

I have developed a REST server with our app specific APIs. we also have deployed a different rest Job server into another location. Currently the way I am doing is .
#RestController
public class SparkJobController {
#Autowired
private IJobSchedulerService jobService;
...
And the Service Implementation is
#Service(value="jobService")
public class JobSchedulerServiceImpl implements IJobSchedulerService {
#Override
public Map triggerJob(String context) {
Map<String, ?> s = new HashMap<String,Object>();
RestTemplate restTemplate = new RestTemplate();
// restTemplate call to other REST API. and returns Map.
...
}
My question is , Is my approach correct ? Or Does Spring framework enables us to use some predefined APIs which can help to use RESTTemplate as a Service
[EDIT] : the deployed REST service is third party application.
I did some research and havent' seen yet a way to implement RestTemplate as a service.
I have seen RestTemplate defined in the bean config and auto wired in - https://www.informit.com/guides/content.aspx?g=java&seqNum=546
To summarize, most of the examples I have seen use Resttemplate, similar to how you have implemented in your code.

Resources