I'm trying to hit external services from one of my microservices. I'm using Spring Cloud, Eureka for the registry and Spring boot as main framework.
Map<String, String> urlVariables = new HashMap<>();
urlVariables.put("ip_address", IP);
urlVariables.put("port", PORT);
ResponseObject state =
restTemplate.getForObject("http://{ip_address}:{port}/state/", ResponseObject.class, urlVariables);
From what I see, Spring Cloud injects Ribbon as the HTTP client for the Rest Template, and when I try to hit this IP (e.g: 193.172.x.x) it produces the following error:
java.lang.IllegalStateException: No instances available for 193.172.x.x
at org.springframework.cloud.netflix.ribbon.RibbonClientHttpRequestFactory.createRequest(RibbonClientHttpRequestFactory.java:64)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:76)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:540)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:247)
It looks like Ribbon is trying to find a microservice instance with that name instead of looking outside. Is there any way to configure Ribbon to look for external IPs, or is it only for internal use?
You are injecting a #LoadBalanced version of RestTemplate. You have to ensure that your RestTemplate is a plain vanilla one. You can just create it with new RestTemplate(). If it's a bean just add a qualifier to ensure you're injecting a proper version of RestTemplate.
On thing you could try is to use the service id in your code and configure the real instances:
ResponseObject state =
restTemplate.getForObject("http://myExternalService/state/", ResponseObject.class, urlVariables);
Than you configure a static list of endpoints for your service
myExternalService.ribbon.listOfServers=http://ip:port
This way you do not use service discovery for this service.
http://projects.spring.io/spring-cloud/docs/1.0.3/spring-cloud.html#spring-cloud-ribbon-without-eureka
Related
I have been using spring-clound-openfeign with Consul as the service registry and Ribbon as Load Balancer. I am currently working with spring-boot 2.3.10.RELEASE.
I really like spring-cloud-feign-inheritance support which, in my understanding, allows me to write a single interface used by the server side and the client side.
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html#spring-cloud-feign-inheritance
From spring-boot 2.4.x onward, the spring team recommended replacing Ribbon by spring-clould-loadbanced as a replacement since Ribbon is no longer being maintained.
If I have an interface let say:
interface Greeting {
#GetMapping
String hello(String name);
}
By using Spring Openfeign + Ribbon + Consul I could just extend it with:
#FeignClient(name="my-service-id")
interface GreetingClient extends Greeting { }
And with that I would have a client implementation with load balanced capabilities.
Can I still accomplish the same result as spring-cloud-openfeign with spring-clould-loadbalancer or I really need to work with RestTemplate or DiscoveryClient to have the client side of my API?
An over all picture of this would be highly appreciated since nonwhere else I have found a sensible answer.
If you want get work like with ribbon, need connect spring cloud loadbalancer to consul. You can read how connnect spring cloud loadbalanncer to consul into link
https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#serviceregistry
I am new to feign client implementation , i have following code for current implementation .
FeignPaymentAbcService:
#FeignClient(name= "abc-service", url="abc url")
public interface FeignPaymentAbcService{
//methods
}
invoking call :
(feignPaymentAbcService.someFunctionality("some input")).getBody();
In future there is possibility of multiple feign services like feignPaymentAbcService ,feignPaymentxyz Service etc so according to service it should get feign client name and url in which service is running.
Basically want to make in dynamic way.
Can anybody suggest any approach ?
You can use the Feign along with Ribbon and Eureka server for dynamically getting the url along with the server( or list of urls depending on instances)
#FeignClient(name= "abc-service")
#RibbonClient(name = "abc-service")
but the name has to be there so that the particular service is identified from the app.properties file.
You need to add corresponding dependencies for eureka server & Ribbon Load balancer and you need to configure them in application.properties
You can lookup my sample code here
Please help. How to configure RestClientProxyFactoryBean in spring boot project
Thx
See this example: It creates a rest client service which you can call to get a rest client instance to make http calls
https://www.programcreek.com/java-api-examples/index.php?source_dir=expressui-framework-master/expressui-domain/src/main/java/com.expressui.domain/RestClientService.java
Usage of this can be seen in the Below link:
https://www.programcreek.com/java-api-examples/index.php?source_dir=expressui-framework-master/expressui-domain/src/main/java/com.expressui.domain/RestClientService.java#
And some test case to be run can be found here:
https://www.programcreek.com/java-api-examples/index.php?source_dir=expressui-framework-master/expressui-domain/src/main/java/com.expressui.domain/RestClientService.java#
Explanation:
So basically we can create different Restclients using proxyfactory bean. In the above example, a service named Geoplanetservice is being created. Rest communication happens via GeoPlanetClient service Interface which is the instantiated via our proxyfactory bean.
I have a spring microservices architecture application but we aren't using eureka or any other service discovery. My requirement is to create a dynamic load balancer. So, for each services there will be unique and dynamic set of servers.
The configuration will be something like:
ribbon:
listOfServices: say-hello-service, say-hi-service
What I don't want to do is, repeat #RibbonClient annotation for each service client that I will use.
I found out that RibbonClientSpecification is the key component of the Ribbon factory. If I register it with names say-hello-service.RibbonClientSpecification and say-hi-service.RibbonClientSpecification, it will try to call respective service even though I don't have #RibbonClient and any Ribbon related configuration. So my questions are
Why is #RibbonClient annotation necessary since we can identify the services from the properties defined? It seems to me that, it is redundant what we have to define ribbon properties in properties file and as well as have the annotation with same name.
How do I register load balancers for each ribbon client that I create dynamically?
What is the right of creating multiple ribbon clients dynamically without having multiple #RibbonClient configuration classes?
You can use its as
#RibbonClient("{services1,service2}")
No need to specify or create new ribbon all the time for different service.
I am working on spring boot application which uses REST webservices. Till now , all the database paaswords i used to store in my application.properties class and am using HICKARI CP also to manage the connection pooling.
But now , i have created the user services in Cloud foundry and have included the script of CF in my build.gradle file too.
But i do not have any idea as to how shall i access these services within my code and how can i autowire thise datasources. Please advice any solution.
Use Spring cloud service connector. This is sub project of Springs cloud.
http://cloud.spring.io/spring-cloud-connectors/spring-cloud-spring-service-connector.html#_relational_database_db2_mysql_oracle_postgresql_sql_server
you can create a mysql service inside your cloud foundry space. And the bind the same to your app. This can be done as defining services inside your manifest.yml or using bind-service command in cf cli.
You can add spring cloud service connector dependencies in your gradle build and add datasource configuration bean.
#Bean
public DataSource dataSource() {
return connectionFactory().dataSource("your-mysql-service-name");
}
This creates a datasource of the mysql service in your application, and registers as a bean in spring context. That can be autowired where ever needed.
Alternatively, cloud foundry exposes the details about every service that application is binded to, in VCAP_SERVICES env variable. Once your application is binded to service, you can find your mysql service username, password, connection url, db name etc in this variable. You can read this variable and parse the values and build a datasource of your own.
Using service connectors are preferred approach as the infrastructure code is handled by springs.