在说这两种方式之前,先来简单的了解一下Ribbon。(之后学习总结)
简单的说Ribbon是一个负载均衡客户端,SpringCloud的两种服务间调用方式背后都用了Ribbon。
一、springCloud 服务间的通信方式有两种
-
RestTemplate 方式
-
Feign 的方式
不管是什么方式,他都是通过REST接口调用服务的http接口,参数和结果默认都是通过jackson序列化和反序列化。
二、使用RestTemplate方式
代码demo接:https://blog.csdn.net/o_darling/article/details/82021616
1. 首先启动springcloud-eureka工程(注册中心),把SpringCloud的服务注册中心启动。
2.在工程springcloud-common(作为服务端)中写一个提供服务的方法
/**
*
* @Title: ServerController.java
* @Package com.common.controller
* @Description: TODO(用一句话描述该文件做什么)
* @author FayQ
* @date 2018年7月6日
* @version V1.0
* @email 1010046660@qq.com
*/
@RestController
@RequestMapping(value="/common")
public class ServerController {
@Value("${server.port}")
private String port;
@GetMapping("/hello")
public String hello() {
return "Hello! I'm server:" + port;
}
}
3.在项目springcloud-common-api中(作为客户端);编写客户端,有三种方式调用方法,如下:
package com.common.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
*
* @Title: ClientController.java
* @Package com.common.controller
* @Description: TODO(用一句话描述该文件做什么)
* @author FayQ
* @date 2018年7月6日
* @version V1.0
* @email 1010046660@qq.com
*/
@RestController
@RequestMapping(value="/client")
public class ClientController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@Value("${server.port}")
private String port;
@GetMapping("/helloClient")
public String helloClient() {
return "Hello! I'm client: " + port;
}
/**
* 第一种方式:直接使用 RestTemplate ,url 写死;
* 因为服务端的 api 被硬编码在客户端,因此有两个缺点:
* – 当注册中心有很多服务时,我们可能不知道我们需要的服务由谁提供、api是多少,因此就可能无法调用到服务。
* –当某个服务部署了多个,例如 api 是: “localhost:8080/hello,localhost:8081/hello “,那么此时就需要负载均衡,这种硬编码显然不符合场景。
*/
@GetMapping("/helloServer1")
public String helloServer1() {
RestTemplate rt = new RestTemplate();
return rt.getForObject("http://192.168.126.31:8001/common/hello", String.class);
}
/**
* 第二种方式:客户端通过 LoadBalancerClient 来获取应用名,进而获取地址和端口,在格式化拼接地址,从而调用 product服务。
* 缺点是每次调用服务都要这样写,编码很麻烦。
*/
@GetMapping("/helloServer2")
public String helloServer2() {
RestTemplate restTemplate = new RestTemplate();
ServiceInstance serviceInstance = loadBalancerClient.choose("spring-cloud-common"); // serviceId 为提供服务的应用名
String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort() + "/common/hello");
String response = restTemplate.getForObject( url, String.class);
return response;
}
/**
* 第三种方式:通过 @LoadBalanced,可在restTemplate 直接使用应用名字。
*/
@GetMapping("/helloServer3")
public String helloServer3() {
return restTemplate.getForObject("http://spring-cloud-common/common/hello", String.class);
}
}
其中第三种方法需要:
@Configuration
public class ConfigBeans {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
测试结果如下:
二、使用Feign方式
1. 添加依赖jar
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类添加@EnableFeignClients
注解
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient //Eureka Client
public class AppMain {
public static void main(String[] args) {
// new SpringApplicationBuilder(AppMain.class).web(true).run(args);
SpringApplication.run(AppMain.class, args);
}
}
3. 定义一个Feign接口
package com.common.consumer.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "spring-cloud-common") // 服务名
public interface ServerService {
@GetMapping("/server/hello")// 这里要和 Product服务提供的接口一致
String hello();
}
4.在配置了Feign接口后,我们就可以直接进行注入调用了
package com.common.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.common.consumer.service.ServerService;
@RestController
@RequestMapping(value="/feignclient")
public class FeignClientController {
@Autowired
private ServerService service;
@GetMapping("/feignHello")
public String feignHello() {
return service.hello();
}
}
测试: