RestTemplate 可以调用其他服务的方法,但是如果别的服务更改了端口,你调用的链接也要更改端口,如果是服务器的ip地址更改了,又要更改对应的链接的ip地址。对于集群来说,如果添加新的服务,又要在里面新增一个地址,如果减少一个服务,如果你不知道端口号,你甚至都不知道删掉哪一个链接地址。耦合度太高。
第一版:不使用Spring Cloud Alibaba
// RestTemplate 的作用就是调用远程接口
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Resource
private RestTemplate restTemplate;
private List<String> urls = Arrays.asList("http://localhost:8081/user", "http://localhost:8083/user", "http://localhost:8084/user");
private int m = 0;
@GetMapping
public List<String> getList() {
List<String> result = restTemplate.getForObject(urls.get(m++ % urls.size()), List.class);
return result;
}
注册中心:eureka(spring cloud)、nacos(spring cloud alibaba)、consul(go)、Redis、zookeeper
Nacos注册中心文件:Nacos注册中心文件
/bin/startup.cmd
# 修改之前的配置(集群模式)
set MODE="cluster"
# 修改之后的配置(单机模式)
set MODE="standalone"
通过nacos,每次当你需要调用其他服务的时候,就回去nacos的注册中心通过名字查询对应服务的端口号和ip地址,然后再去调用该服务,这时候就跟nacos没有任何关系了,nacos就算挂掉,只要服务的ip地址和端口号没有改变,都不会有任何影响。如果服务的IP地址或者端口号进行了改变,则当该服务重新启动时,就会在nacos注册中心将信息重新注册。然后当你发现你调用该服务调用不通了,你就会去问nacos,然后nacos就会将更新后的地址信息重新告诉你。
Nacos yml配置文件
server:
port: 8083
spring:
application:
# 应用的服务名词
name: ms-provider
cloud:
nacos:
discovery:
# nacos 的地址
server-addr: localhost:8848
# 是否将自己的服务注册到nacos上去
register-enabled: true
第二版:Nacos 版本
@Resource
private RestTemplate restTemplate;
@Resource
private DiscoveryClient discoveryClient;
private int m = 0;
@GetMapping
public List<String> getList() {
// ms-provider 可能是个集群
List<ServiceInstance> instances = discoveryClient.getInstances("ms-provider");
ServiceInstance instance = instances.get(m++ % instances.size());
String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/user";
List<String> result = restTemplate.getForObject(url, List.class);
return result;
}
第三版:Ribbon 默认是轮询策略,可以不需要通过轮询的方式去获取服务,通过负载均衡的方式去获取。
// RestTemplate 的作用就是调用远程接口
@Bean
@LoadBalanced // 使用Ribbon负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Resource
private RestTemplate restTemplate;
@GetMapping
public List<String> getList() {
List<String> result = restTemplate.getForObject("http://ms-provider/user", List.class);
return result;
}
@Bean
public IRule rule() {
// 默认就是轮询的负载均衡的策略
return new RoundRobinRule();
return new RandomRule(); // 随机的负载均衡策略
return new NacosRule();
}
第四版:Feign Ribbon的基础上又增加了负载均衡策略,像调本地方法一样调用其他服务的方法。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {
public static void main( String[] args ) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
@Component
public class AppConfig {
// RestTemplate 的作用就是调用远程接口
@Bean
@LoadBalanced // 使用Ribbon负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 因为 feign 是基于 ribbon, 如果使用的默认的负载均衡策略(轮询的方式) 那么可以
// 不在容器中纳入一个 IRule 类型的 Bean; 如果要使用其他的负载均衡策略,需要在IOC
// 容器中纳入一个 IRule 类型的Bean
@Bean
public IRule rule() {
// 默认就是轮询的负载均衡的策略
return new RoundRobinRule();
return new RandomRule(); // 随机的负载均衡策略
return new NacosRule();
}
}
/*
* 400 请求参数错误
* 401 认证失败
* 403 没有权限
* 404 找不到资源
* 405 请求方式错误
* 500 服务器内部错误
*/
@FeignClient(value = "ms-provider")
public interface UserService {
// http://ms-provider/user
@GetMapping("/user/all")
AjaxResult getAll();
/**
* 1.feign 如果检测到方法调用的时候有传递参数,并且参数没有加 @RequestParam,
* 默认发送POST请求,会无视 @GetMapping
* 2.需要在参数前面加上 @RequestParam
*/
@GetMapping("/user/id")
AjaxResult getWithId(@RequestParam Integer id);
// 在feign的调用过程,方法的参数会反向绑定到路径的参数中
@GetMapping("/user/{id}")
AjaxResult getById(@PathVariable("id") Integer id);
@GetMapping("/user")
AjaxResult getWithMultipleCriteria(@RequestParam String name, @RequestParam Integer id);
@PostMapping("/user")
AjaxResult add(User user);
@DeleteMapping("/user/{id}")
AjaxResult deleteById(@PathVariable("id") Integer id);
@PutMapping("/user")
AjaxResult edit(User user);
}
@Resource
private UserService userService;
@GetMapping
public AjaxResult getAll() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(102);
return userService.getAll();
}
@GetMapping("/{id}")
public AjaxResult getWithId(@PathVariable("id") Integer id) {
return userService.getWithId(id);
}
// http://localhost:8082/cuc/id/45
@GetMapping("/id/{id}")
public AjaxResult getById(@PathVariable("id") Integer id) {
return userService.getById(id);
}
// http://localhost:8082/cuc/multi-param?name=zs&id=123
@GetMapping("/multi-param")
public AjaxResult getWithMultipleCriteria(String name, Integer id) {
return userService.getWithMultipleCriteria(name, id);
}
// http://localhost:8082/cuc/add?name=lisi&id=123
@GetMapping("/add")
public AjaxResult add(String name, Integer id) {
return userService.add(new User(id, name));
}
// http://localhost:8082/cuc/delete/1235
@GetMapping("/delete/{id}")
public AjaxResult delete(@PathVariable("id") Integer id) {
return userService.deleteById(id);
}
// http://localhost:8082/cuc/edit?name=zs&id=123
@GetMapping("/edit")
public AjaxResult edit(String name, Integer id) {
return userService.edit(new User(id, name));
}