一、springCloud 服务间的通信方式有两种
- RestTemplate 方式
- Feign 的方式
二、RestTemplate 方式
RestTemplate 中也分为三种方式
简单来演示一下吧
-
第一种方式
直接使用 RestTemplate ,url 写死服务端编写
/**
- 用来测试与 order 服务的连接
- @author ccyang
- @date 2018/7/1 16:06
*/
@RestController
public class serverController {
@GetMapping(“/getMsg”)
public String getMsg(){
return “this is product’ msg”;
}
}
客户端编写
/**
* @author ccyang
* @date 2018/7/1 16:13
*/
@RestController
@Slf4j
public class clientController {
@GetMapping("/getProductMsg")
public String getProductMsg(){
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject("http://localhost:8080/getMsg",String.class);
log.info("response = {}" , response);
return response;
}
}
然后去访问 http://localhost:8080/getMsg 即可。
因为服务端的 api 被硬编码在客户端,因此有两个缺点:
– 当注册中心有很多服务时,我们可能不知道我们需要的服务由谁提供、api是多少,因此就可能无法调用到服务。
–当某个服务部署了多个,例如 api 是: “localhost:9080/getMsg,localhost:9081/getMsg “,那么此时就需要负载均衡,这种硬编码显然不符合场景。
-
第二种方式:
service端代码依旧,客户端通过 LoadBalancerClient 来获取应用名,进而获取地址和端口,在格式化拼接地址,从而调用 product服务。如下:/**
-
测试获取 product服务的msg
-
@author ccyang
-
@date 2018/7/1 16:13
*/
@RestController
@Slf4j
public class clientController {@Autowired
private LoadBalancerClient loadBalancerClient;@GetMapping(“/getProductMsg”)
public String getProductMsg(){RestTemplate restTemplate = new RestTemplate(); ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT"); // serviceId 为提供服务的应用名 String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort() + "/getMsg"); String response = restTemplate.getForObject( url, String.class); log.info("response = {}" , response); return response;
}
}
-
缺点是每次调用服务都要这样写,编码很麻烦。
-
第三种方式
通过 @LoadBalanced,可在restTemplate 直接使用应用名字。@Component
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}@RestController
@Slf4j
public class clientController {@Autowired private RestTemplate restTemplate; @GetMapping("/getProductMsg") public String getProductMsg(){ String response = restTemplate.getForObject( "http://PRODUCT/getMsg", String.class); // 通过应用名进行访问 log.info("response = {}" , response); return response; }
}
三、使用 Feign 的方式进行通信
- 声明式 REST客户端(伪 RPC)
- 采用了基于接口的注解
先看看如何使用 Feign:
1. 添加依赖
<!-- add feign , note: must add version -->
<dependency>
<groupId>org.springframework.cloud</groupId >
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
2. 添加注解到主类上
@EnableFeignClients
3. 定义要调用的接口
@FeignClient(name = "product") // 服务名
public interface ProductClient {
@GetMapping("/getMsg") // 这里要和 Product服务提供的接口一致
String productMsg();
}
4. 在该使用的地方使用注解中提供的方法
@RestController
@Slf4j
public class clientController {
@Autowired
private ProductClient productClient; // 有报错,不影响
@GetMapping("/getProductMsg")
public String getProductMsg(){
String response = productClient.productMsg();
log.info("response = {}" , response);
return response;
}
}
Feign 可以看做是一个伪 RPC,而且HTTP远程调用对开发者完全透明。
RestTemplate 内部使用 Ribbon做负载均衡
Feign 内部也是使用的Ribbon做负载均衡