声明式服务调用:Spring Cloud Feign
一、Feign、Ribbon、Hystrix
1.基本介绍
- 前面使用Spring Cloud Ribbon和Spring Cloud Hystrix,实现了申请活动服务中申请完活动后调用邮件服务发送邮件的功能,以此实践了客户端负载均衡的服务调用和通过断路器保护微服务应用。
- 在实践过程中,这两个框架几乎同时出现和使用,并且用起来比较麻烦。Spring Cloud Feign就是Ribbon和Hystrix更高层次的封装。
- Feign基于Netflix Feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,即我们可以不再使用Ribbon和Hystrix而直接使用Feign以简化开发。
- Feign除了提供Ribbon和Hystrix两者强大的功能外,它该提供了一种声明式的Web服务客户端定义方式。
2.调用其他服务方式的改变
- 使用Ribbon调用其他服务:
之前使用Ribbon调用其他服务是使用restTemplate发送请求,不太友好:
restTemplate.getForEntity("http://SCLOUD-EMAIL-SERVICE/api/email/simple/[email protected]&subject=活动申请&content=aa", String.class).getBody();
-
使用Feign调用其他服务:
使用Feign时,创建一个接口(Interface)并配置它指向邮件服务,再在这个接口中声明方法并配置指向邮件服务的某个Restful Api接口。在活动申请服务中调用接口名.方法名就能调用到邮件服务 -
Feign只需定义服务绑定接口,以声明的方法,优雅而简单的实现了服务调用。
二、简单使用Feign
1.要实现的功能
2.邮件服务编写发送邮件的Restful Api
// 邮件服务
@RestController
@RequestMapping("/api/email")
public class EmailSendController {
// 发送邮件服务
@GetMapping(value = "/send")
public String sendEmail(){
System.out.println("邮件服务-发送邮件");
return "send ok";
}
}
3.活动申请服务添加依赖
pom.xml中添加Feign依赖
<!--Feign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
4.启用Feign
添加@EnableFeignClients注解
@EnableEurekaClient
@EnableFeignClients
@SpringBootApplication
public class ActivimanageApplication {
public static void main(String[] args) {
SpringApplication.run(ActivimanageApplication.class, args);
}
}
5.定义接口并配置指向邮件服务的发送邮件接口
@FeignClient中填写邮件服务的服务名
// 配置该接口指向邮件服务
@FeignClient(value = "SCLOUD-EMAIL-SERVICE")
public interface EmailFeign {
// 配置该方法指向邮件服务的发送邮件API
@RequestMapping("/api/email/send")
String sendEmail();
}
这样配置完成后调用 EmailFeign.sendEmail()即可相当于发送 [邮件服务/api/email/send] 这个请求。
6.在活动申请服务中使用Feign调用邮件服务
// 活动申请服务
@RestController
@RequestMapping("/api/activity")
public class ActivityApplyController {
@Autowired
private ActivityApplyService service;
// 申请活动接口
@GetMapping(value = "/simple/apply")
public void applySimpleActivity(){
// 调用Service层执行申请活动的逻辑
String emailServiceRs = service.applyActivi();
return emailServiceRs;
}
}
Service层
@Service
public class ActivityApplyService {
@Autowired
private EmailFeign emailFeign;
public String applyActivi(){
System.out.println("申请活动...");
// 使用Feign调用邮件服务
String rs = emailFeign.sendEmail();
return rs ;
}
}
7.使用
访问活动申请服务的活动申请接口,正确返回了邮件服务的结果
三、Feign的负载均衡
上面实现了使用Feign进行远程服务调用,再看一下它的负载均衡。
1.启动两个邮件服务
- 邮件服务节点1配置文件, 启动在8003端口
server:
port: 8003
spring:
application:
name: SCLOUD-EMAIL-SERVICE # 邮件服务名
# Eureka配置
eureka:
client:
service-url:
defaultZone: http://peer1:9091/eureka/,http://peer2:9092/eureka/,http://peer3:9093/eureka/ # 指定注册中心地址
- 邮件服务节点2配置文件, 启动在8004端口
server:
port: 8004
spring:
application:
name: SCLOUD-EMAIL-SERVICE # 邮件服务名
# Eureka配置
eureka:
client:
service-url:
defaultZone: http://peer1:9091/eureka/,http://peer2:9092/eureka/,http://peer3:9093/eureka/ # 指定注册中心地址
- 启动两个邮件服务
2.多次调用申请活动接口,查看邮件服务被调用情况
发现它是被轮询调用的。
3.总结
- Feign实现的服务调用,依然是利用Ribbon,定时向Eurek注册中心查询服务列表,维护了一个邮件服务的列表,轮询进行调用实现了负载均衡。具体如何工作的前面Ribbon那篇博客有一个图。
四、使用Feign进行复杂接口的跨服务调用
以上是较简单接口的跨服务调用,实际开发过程中,我们会遇到各种复杂的接口。
1.邮件服务新增三个接口
新增一个邮件实体
@Data
public class Email {
/** 收件人 */
private String to;
/** 邮件内容 */
private String content;
/** 发送结果 */
private String rs;
}
新增三个接口,基本涵盖了我们日常开发中用到的
// 邮件服务
@RestController
@RequestMapping("/api/email")
public class EmailSendController {
// GET发送邮件:参数为[邮件信息字符串] 返回邮件实体
@PostMapping(value = "/send/dto/re/dto")
public Email emailPostDtoReDto(@RequestParam("to") String to, @RequestParam("content") String content){
Email email = new Email();
email.setTo(to);
email.setContent(content);
email.setRs("send ok!");
return email;
}
// POST发送邮件:参数为[邮件信息实体] 返回邮件实体
@PostMapping(value = "/send/dto/re/dto")
public Email emailPostDtoReDto(@RequestBody Email email){
email.setRs("send ok!");
return email;
}
// POST发送邮件:参数为[邮件信息实体] 返回字符串
@PostMapping(value = "/send/dto/re/str")
public String emailPostDtoReStr(@RequestBody Email email){
return "send ok";
}
}