Fork me on GitHub

SpringCloud微服务之间的通信

1. 服务之间的通信

应用之间通信的常见的两种方式是http和RPC方式。典型的代表框架就是SpringCloud和Dubbo

SpringCloud中使用RestTemplate实现应用间的通信。举一个简单的例子来实现下。

现在有订单和商品两个服务,现在要时候订单服务去调用商品服务。

商品服务端

1
2
3
4
5
6
7
8
@RestController
public class ServerController {

@GetMapping("/msg")
public String msg(){
return "this is product msg";
}
}

订单服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
@Slf4j
public class ClientController {

@GetMapping("/getProductMsg")
public String getProductMsg(){
//1.第一种方式
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject("http://localhost:8080/msg",String.class);
log.info("response={}", response);
return response;
}

}

1

访问可以得到商品服务端返回的信息。

上面的方式要访问固定的URL,这样就肯定是不方便的,假如上面的应用我有多个地址,或者当你根本不知道地址的时候怎么办?

第二种方式使用LoadBalancerClient通过应用名获取URL等信息。

1
2
3
4
5
6
7
8
9
@Autowired
private LoadBalancerClient loadBalancerClient;

RestTemplate restTemplate = new RestTemplate();
ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT");
String url = String.format("http://%s:%s",serviceInstance.getHost(), serviceInstance.getPort()) + "/msg";
String response = restTemplate.getForObject(url,String.class);
log.info("response={}", response);
return response;

loadBalancerClient.choose(“PRODUCT”);中的PRODUCT是你的服务注册在server端的名字

第三种方式使用注解的方式

首先配置一个类

1
2
3
4
5
6
7
8
9
@Component
public class RestTemplateConfig {

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

在controller中配置如下:PRODUCT为微服务的应用名

1
2
3
4
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject("http://PRODUCT/msg",String.class);
log.info("response={}", response);
return response;

2. 客户端的负载均衡器-Ribbon

SpringCloud是客户端发现,他的负载均衡是软负载均衡,也就是eureka通过拉取已经注册的服务,然后通过负载均衡策略直接命中相应的服务。SpringCloud中的客户端的负载均衡器是Ribbon

Ribbon下的组件主要有:ServerList,IRule,ServerListFilter等,主要流程是通过serverlist获取所有可用的服务列表,然后ServerListFilter会过滤掉一部分的地址,最后使用IRule从剩下的服务列表中选择一个实例作为最后的目标。

Ribbon中的负载均衡的策略是通过轮询的方式实现的。要是想改变负载均衡的策略的话可以在yml文件中配置如下:

1
2
3
4
users:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

不同的版本的配置可能不同我这里的版本是Greenwich.RC2。具体的可以去官网查看Reference Doc.users是你的微服务的名字

3. Spring Cloud 声明式服务调用 Feign

上面说到Ribbon做的负载均衡是用的Spring提供RestTemple来做的请求。

Springcloud的Fegin组件,这个组件是Spring提供的封装好的跨服调用组建可以使服务之间的调用更为便捷。

官网有介绍是怎么使用的:https://cloud.spring.io/spring-cloud-static/Greenwich.RC2/multi/multi_spring-cloud-feign.html#netflix-feign-starter

引入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在启动应用中添加注解

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {

public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}

}

声明你要调用的是那些服务的那些接口

1
2
3
4
5
6
@FeignClient(name = "product")  
public interface ProductClient {

@GetMapping("/msg")
String productMsg();
}

name属性是你的服务名,@GetMapping(“/msg”)下的地址是你要调用的接口。也就是你的服务下要有这个接口,要不然你调用的是个锤子。

在客户端调用的时候直接使用上面的类实现调用即可,注意的是对应好返回类型。

1
2
3
4
5
6
7
8
9
10
public class ClientController {
@Autowired
ProductClient productClient;

@GetMapping("/getProductMsg")
public String getProductMsg(){
String response = productClient.productMsg();
return response;
}
}

通过上面我们发现它使用的是基于接口的注解的方式实现服务之间的调用。

当你的方法中有@RequestBody时,请使用@PostMapping的注解,因为你传入的不止一个参数。但是当你使用@PathVarible,@ReauestParam或者是无参数传入的时候可以使用@GetMapping的注解,其实最主要的是看你的前端请求是post方式还是get方式。

注意:

Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException)

4. 多服务拆分

使用上面的ribbon的方式实现了应用间的调用,但是发现每个应用之间是存在冗余的部分的,可以把这些东西抽取出来做成公共的模块,然后有一些互相调用的东西也可以做成公共的接口去实现。

本文标题:SpringCloud微服务之间的通信

文章作者:WilsonSong

发布时间:2019年01月17日 - 21:01

最后更新:2019年03月09日 - 21:03

原始链接:https://songwell1024.github.io/2019/01/17/SpringCloudCommunition/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢您的阅读-------------