前言
在上次的文章中我们认识了微服务和微服务的常用框架SpringCloud与Dubbo,以及SpringCloud的Eureka组件。Eureka负责SpringCloud体系中的服务治理与发现,它可以实现注册在Eureka上的服务相互调用。上次的演示中我们创建了注册中心eureka-server和服务提供者provider-demo并将provider-demo注册到了eureka-server上,那么对于服务调用者consumer该如何调用服务提供者所提供的服务呢?这就是我们今天要讲的Feign组件。
上一篇: 微服务SpringCloud新手入门(一)
下一篇: 微服务SpringCloud新手入门(三)
Feign
作用:实现服务之间的远程调用
简介:Spring Cloud Feign是Spring Cloud 体系中的重要组件。是一款基于注解和动态代理实现的声明式restful http客户端。
调用方式
微服务架构项目之间一般有两种调用方式,即RPC和RESTful。
(1)RPC
RPC即Remote Procedure Call(远程过程调用),通俗的讲,就是可以在一个项目中像调用本地服务一样去掉用其他项目的服务。在Dubbo中的具体调用方式是使用@DubboConsumer注解注入到Service为其他项目服务。
(2)RESTful
REST全称是Representational State Transfer,是一组架构约束条件和原则。狭义上,RESTful可以理解为在Web请求中,将参数封装于URL内部。在微服务中,项目之间可以采用RESTful风格的HTTP方式互相进行调用。常见的微服务框架,如Spring Cloud及Dubbox均支持RESTful的调用方式。
底层原理
SpringCloud和dubbo都是实现服务之间的远程调用,但是底层是基于两种不同的方式:
dubbo底层是使用Netty的NIO框架,基于TCP协议传输,使用Hession序列化完成RPC通信。RPC是介于应用层和传输层之间的协议,调用者执行接口时可找到其他进程的函数体,是通过socket交互字节流实现的,调用者通过服务注册中心(例如zookeeper)找到被调用者的服务,生成代理对象,序列化跟反序列化达到请求。
SpringCloud底层是基于HTTP协议传输,比较简单,不像dubbo需要自己写底层源码实现传输。正是因为需要遵循HTTP协议,从通信效率来说当然比不过dubbo的二进制传输,但是SpringCloud是多语言开发的,大家都只需要遵循HTTP协议便能整合在一起,如GO,C++等语言。而dubbo只能基于Java开发。
示例
示例springcloud版本为Hoxton.SR3,springboot版本为2.2.5
参数为String
在上次示例的基础上:
1.在provider-demo项目中增加Service包
在Service包中编写具体提供服务的类:
@RestController
public class UserService {
private Logger logger = LoggerFactory.getLogger(UserService.class);
@RequestMapping(value="/login",method = RequestMethod.POST)
public boolean login(@RequestParam("name") String name,@RequestParam("pwd")String pwd) throws Exception{
return "admin".equals(name)&&"123456".equals(pwd);
}
}
2.创建consumer-demo项目
因为要注册到eureka-server上,所以创建时需要勾选Eureka Discovery Client,除此之外别忘了勾选OpenFeign
application.yml配置如下:
server:
port: 8089
spring:
application:
name:consumer-demo
eureka:
client:
service-url:
defaultZone: http://admin:123456@localhost:8761/eureka/
添加service包,并在service包中编写具体调用服务的接口与控制器:
@FeignClient(name="provider-demo")
public interface UserFeignClient {
@RequestMapping(value="/login",method = RequestMethod.POST)
public boolean login(@RequestParam("name") String name, @RequestParam("pwd")String pwd);
}
@RestController
public class LoginController {
@Autowired
private UserFeignClient userFeignClient;
@RequestMapping(value="/userlogin",method = RequestMethod.POST)
public String login(@RequestParam("name") String name, @RequestParam("pwd")String pwd){
if(userFeignClient.login(name,pwd)){
return "hello!"+name;
}else{
return "fail,"+name;
}
}
在启动类上添加@@EnableEurekaClient和@EnableFeignClients,
依次启动eureka-server,provider-demo,consumer-demo并访问http://localhost:8761
成功将consumer-demo注册到eureka-server,使用Restlet Client测试http://localhost:8089/userlogin
可以看到服务调用成功!UseFeignClient虽然是接口,但依然可以被调用,原因就是Feign,它把LoginController发送过来的请求通过http的形式发送给了provider-demo中的UserService,相当于UserService是UseFeignClient接口的实现类,真正实现了功能。
以上是请求参数为两个String的服务调用情况,那么如果参数为复杂数据类型(JavaBean)的调用情况又是怎样呢?
参数为User(JavaBean)
1.创建公共模块项目common
common无需注册到eureka-server上,因此可以创建为普通maven项目
在common中编写User类:
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
编写完成之后install到本地仓库供其他服务调用。
2.修改provider-demo与consumer-demo
在provider-demo和consumer-demo中添加common的依赖:
<dependency>
<groupId>com.example</groupId>
<artifactId>commom</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
修改provider-demo的UserService类:
public class UserService {
private Logger logger = LoggerFactory.getLogger(UserService.class);
@RequestMapping(value="/login",method = RequestMethod.POST)
public boolean login(@RequestBody User user) throws Exception{
return "admin".equals(user.getUsername())&&"123456".equals(user.getPassword());
}
}
修改consumer-demo的UserFeignClient接口:
@FeignClient(name="provider-demo")
public interface UserFeignClient {
@RequestMapping(value="/login",method = RequestMethod.POST)
public boolean login(@RequestBody User user);
}
修改consumer-demo的LoginController类:
@RestController
public class LoginController {
@Autowired
private UserFeignClient userFeignClient;
@RequestMapping(value="/userlogin",method = RequestMethod.POST)
public String login(@RequestBody User user){
if(userFeignClient.login(user)){
return "hello!"+user.getUsername();
}else{
return "fail,"+user.getUsername();
}
}
}
修改完成之后依次启动eureka-server,provider-demo,consumer-demo并使用Restlet Client测试http://localhost:8089/userlogin:
服务成功调用!
(SpringCloud其他组件将在下次更新 (ง •̀_•́)ง,如有错误,希望大家多多指正(•‾̑⌣‾̑•)✧˖°)