初体验springcloud微服务不同模块之间的服务调用
在order模块,创建一个controller,用于调用video模块的api
@RestController
@RequestMapping("api/v1/video_order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/save")
public Object save(int videoId){
Video video = restTemplate.getForObject("http://localhost:9000/api/v1/video/find_by_id?videoId="+videoId, Video.class);
VideoOrder videoOrder = new VideoOrder();
videoOrder.setVideoId(video.getId());
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setCreateTime(new Date());
return videoOrder;
}
}
在启动函数中添加@Bean注解方法,RestTemplate就是可以获得别的模块Api的类
@SpringBootApplication
public class OrderApplication {
public static void main(String [] args){
SpringApplication.run(OrderApplication.class,args);
}
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
在video模块中,controller
@RestController
@RequestMapping("api/v1/video")
public class VideoController {
@Autowired
private VideoService videoService;
@RequestMapping("find_by_id")
public Object findById(int videoId){
return videoService.findById(videoId);
}
}
两个模块都运行之后,访问 localhost:8000/api/v1/video_order/save?videoId=40发现成功
缺点
- 服务之间的IP信息写死
- 服务之间⽆法提供负载均衡
- 多个服务直接关系调⽤维护复杂
通过Nacos来管理微服务
- 服务注册:服务提供者provider,启动的时候向注册中
⼼上报⾃⼰的⽹络信息 - 服务发现:服务消费者consumer,启动的时候向注册中⼼上报⾃⼰的⽹络信息,拉取provider的相关⽹络信息
- 核⼼:服务管理,是有个服务注册表,⼼跳机制动态维护,服务实例在启动时注册到服务注册表,并在关闭时注销。
- 微服务应⽤和机器越来越多,调⽤⽅需要知道接⼝的⽹络地址,如果靠配置⽂件的⽅式去控制⽹络地址,对于动态新增机器,维护带来很⼤问题
使用方法
下载nacos安装包之后,解压,在bin目录启动
sh startup.sh -m standalone
然后浏览器访问 localhost:8848/nacos,默认账号密码都是nacos
然后再在每个服务模块添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
每个application.yml文件添加配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
然后再在每个启动类上添加注解
@EnableDiscoveryClient
然后再在Order的controller中更改
@RestController
@RequestMapping("api/v1/video_order")
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient; //通过它可以获得请求的url和端口号
@Autowired
private RestTemplate restTemplate;
@RequestMapping("save")
public VideoOrder save(int videoId){
VideoOrder videoOrder = new VideoOrder();
videoOrder.setVideoId(videoId);
//获取到对应的服务的相关信息
List<ServiceInstance> list = discoveryClient.getInstances("wpb-video-service");
ServiceInstance si = list.get(0);
//通过ServiceInstance获取到他的url和端口号,这些信息都在nacos中注册过了
Video video = restTemplate.getForObject("http://"+si.getHost()+":"+si.getPort()+
"/api/v1/video/find_by_id?videoId="+videoId,Video.class);
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setVideoId(video.getId());
return videoOrder;
}
}
然后重启项目可以看到
通过postman测试成功
不过这个时候并没有考虑到负载均衡的问题,对于一个服务来说依然只是一台服务器,常见的负载均衡策略有
- 节点轮询
-- 简介:每个请求按顺序分配到不同的后端服务器 - weight 权重配置
-- 简介:weight和访问比率成正比,数字越大,分配得到的流量越高 - 固定分发
-- 简介:根据请求按访问ip的hash结果分配,这样每个用户就可以固定访问一个后端服务器
Ribbon的使用
Ribbon是一个客户端负载均衡工具,通过Spring Cloud封装,可以轻松和AlibabaCloud整合
使用也比较简单,在order的启动类
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
其他的不变,这样就开启了负载均衡
Ribbon支持的负载均衡策略介绍
然后使用的话有一个注意点,在order模块调用的时候
@RestController
@RequestMapping("api/v1/video_order")
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient; //通过它可以获得请求的url和端口号
@Autowired
private RestTemplate restTemplate;
@RequestMapping("save")
public VideoOrder save(int videoId){
VideoOrder videoOrder = new VideoOrder();
videoOrder.setVideoId(videoId);
//获取到对应的服务的相关信息
List<ServiceInstance> list = discoveryClient.getInstances("wpb-video-service");
ServiceInstance si = list.get(0);
//通过ServiceInstance获取到他的url和端口号,这些信息都在nacos中注册过了
//如果使用了ribbon,这个就只能使用服务的名字了
// String url = "http://"+si.getHost()+":"+si.getPort()+
// "/api/v1/video/find_by_id?videoId="+videoId;
// System.out.println(url);
Video video = restTemplate.getForObject("http://wpb-video-service/api/v1/video/find_by_id?videoId="+videoId,Video.class);
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setVideoId(video.getId());
videoOrder.setServerInfo(video.getServeInfo());
return videoOrder;
}
}
Ribbon不规范,风格不统一,维护性比较差
新的负载均衡组件Feign
不用像Ribbon中通过封装HTTP请求报文的方式调用 Feign默认集成了Ribbon
Nacos支持Feign,可以直接集成实现负载均衡的效果
- 加入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 在每个启动类上加上注解
@EnableFeignClients
- 在Order模块里service里添加
@FeignClient(value = "wpb-video-service")
public interface VideoService {
@GetMapping("/api/v1/video/find_by_id")
Video findById(@RequestParam("videoId") int videoId);
@PostMapping("/api/v1/video/save")
int save(@RequestBody Video video);
}
然后就可以在Order模块中的controlle里直接调用了,就像调用自己的service方法一样