使用Ribbon+RestTemplate来实现微服务间的调用

一、Ribbon

        Ribbon是Spring Cloud下的一个组件,是一个基于HTTP和TCP的客户端负载均衡工具,是一个负载均衡框架,是基于Netflix实现。我们可以通过Ribbon来实现服务间的调用,同时还可以实现各客户端服务间的负载均衡。

1.现有2个服务,一个为expense,另一个为payment服务,准备使用ribbon实现服务间的调用,payment服务调expense

expense服务为服务的提供方,代码如下:

@RestController 
@RequestMapping("/api/report") 
public class ReportController { 

 @GetMapping("/get/info/by/id") 
  public String getInfo(){
   return "success"; 
 } 
}

payment服务为服务的消费方:

@RestController 
@RequestMapping("/api/wallet") 
public class DataContoller { 
  @Autowired WalletService walletService;
    @GetMapping("/hello") public String sayHello(){ 
     return walletService.sayHello(); 
   }
 }

service类代码:

@Service 
public class WalletService { 

 @Autowired RestTemplate restTemplate;

 public String sayHello() { 
   String str=restTemplate.getForObject("http://localhost:9096/api/report/get/info/by/id",String.class); 
  System.out.println(str); 
  return "expense服务下的:"+str; 
 } 
}

可以发现:我们使用了RestTemplate 类,此处需要写一个Bean,该Bean为:

@Bean
@LoadBalanced 
RestTemplate restTemplate(){ 
  return new RestTemplate(); 
}

springboot启动的时候,将该Bean装载到spring容器里。

记一下在学习ribbon中遇到的问题:

第一次调用出现如上错误。

服务的代码为:

String str= restTemplate.getForObject("/api/report/get/info/by/id",String.class);

把它修改为:

还是出错

加上http,将url修改为:

String str= restTemplate.getForObject("http://expense/api/report/get/info/by/id",String.class);

再次访问:

调用成功!

接着我们去掉@LoadBalanced注解,不用@LoadBalanced注解,就可以使用使用ip地址来获取expense服务。

@Bean RestTemplate restTemplate(){ return new RestTemplate(); }

String str= restTemplate.getForObject("http://localhost:9096/api/report/get/info/by/id",String.class);

访问如下url, 同样调用成功!

这是为什么呢?

问题是: 当有@LoadBalanced注解时,RestTemplate会根据eureka服务上的应用名去寻找主机。因此调用的时候需要加上eureka上面的应用名。

请求的url为:

String str= restTemplate.getForObject("http://expense/api/report/get/info/by/id",String.class);

这样就能调用成功了!结果如上

2. 怎么请求带有参数的url?

比如我们要传一个id的get请求。

报错:

被调用方:

Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required Long parameter 'id' is not present]

调用方:

org.springframework.web.client.HttpClientErrorException$BadRequest: 400 null

查看源码后,发现getForObject方法的第三个参数需要传一个map,修改代码如下:

此处的RestTemplate没有加上@LoadBalanced注解,如果加的话,url的host需要修改为应用名。

package com.example.hand.wallet.service; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 
import org.springframework.web.client.RestTemplate; 
import java.util.HashMap; 
import java.util.Map; 

@Service 
public class WalletService { 
  @Autowired RestTemplate restTemplate; 
  public String sayHello() { 
     Long id=1L; 
    Map<String,Integer> map=new HashMap<>();
    map.put("id",1); String str= 
  restTemplate.getForObject("http://localhost:9096/api/report/get/info/by/id?id= {id}",String.class,map); 
  System.out.println(str); 
return "expense服务下的:"+str; } }

再次访问:

看一下RestTemplate类的源码:

可以找到常用的GET请求和POST请求对应的方法:

GET请求:

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)

public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables);

public <T> T getForObject(URI url, Class<T> responseType) ;

POST 请求:

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) ;

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables);

public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType);
发布了53 篇原创文章 · 获赞 45 · 访问量 8823

猜你喜欢

转载自blog.csdn.net/qq_33036061/article/details/103590945