目录
一、Feign介绍
1、什么Feign
Feign是Spring Cloud提供的声明式、模板化的HTTP客户端, 它使得调用远程服务就像调用本地
服务一样简单,只需要创建一个接口并添加一个注解即可。
Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解;Feign默认集成了
Ribbon,所以Fegin默认就实现了负载均衡的效果。【(ribbon+restTemplate)+优化=feign】
2、Feign的启动器
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在FeignConsumerApp启动器类上添加 @EnableFeignClients 注解,开启feign注解的扫描
@SpringBootApplication
@EnableDiscoveryClient//向注册中心注册该服务,并可以获取其他服务的调用地址
@EnableFeignClients//开启feign注解的扫描
public class FeignConsumerApp {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApp.class);
}
}
二、Feign入门案例
1.创建服务提供者feign_provider
注:feign_provider模块是拷贝的ribbo_provider_1模块,在下面内容中所使用到的代码案例均来自前面几篇内容中的代码案例。
application.xml文件
server:
port: 9090
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.238.132:8848 #nacos服务的地址
application:
name: feign-provider #向注册中心注册的名字
controller层
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Autowired
private UserService userService;
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
return userService.getUserById(id);
}
@RequestMapping("/deleteUserById")
public User deleteUserById(Integer id){
return userService.deleteUserById(id);
}
@RequestMapping("/addUser")
public User addUser(@RequestBody User user){
return userService.addUser(user);
}
}
service包中改动内容
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserById(Integer id) {
return new User(id,"王小",18);
}
@Override
public User deleteUserById(Integer id) {
return new User(id,"删除了王小",18);
}
@Override
public User addUser(User user) {
user.setName("新增王小");
return user;
}
}
2.创建feign_interface模块
pom.xml
<dependencies>
<!--Spring Cloud OpenFeign Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.wrs</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
UserFeign接口: 分别使用了三种不同的请求发送的方式
@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserFeign {
@RequestMapping("/getUserById/{id}")//拼接url
public User getUserById(@PathVariable("id") Integer id);//restful形式拼接参数
@RequestMapping("/deleteUserById")//拼接url
User deleteUserById(@RequestParam("id") Integer id);//?形式拼接参数
@RequestMapping("/addUser")
User addUser(@RequestBody User user);//pojo--->json
}
3.创建服务消费者feign_consumer
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.wrs</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--feign接口-->
<dependency>
<groupId>com.wrs</groupId>
<artifactId>feign_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
application.yml
server:
port: 80
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.238.132:8848
application:
name: feign-consumer
Controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserFeign userFeign;//代理类
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
System.out.println(userFeign.getClass());
return userFeign.getUserById(id);
}
@RequestMapping("/deleteUserById")
public User deleteUserById(Integer id){
System.out.println(userFeign.getClass());
return userFeign.deleteUserById(id);
}
@RequestMapping("/addUser")
public User addUser(User user){
System.out.println(userFeign.getClass());
return userFeign.addUser(user);
}
}
feign_consumer的启动器在上方内容已经给出为FeignConsumerApp,请参考上方内容;
4.案例测试
分别对三个请求方法进行了测试,根据注解的不同输入的请求路径也不相同,由此可知:
在UserFeign接口中
1、@RequestMapping 表示拼接请求路径 localhost/consumer/getUserById/2
是restful传参
2、@PathVariable("id") 表示 ? 形式拼接参数 localhost/consumer/deleteUserById?2
?传参3、@RequestBody 表示“对象”转“JSON”传参 localhost/consumer/addUser?id=2&name=wx&age=18
pojo---->json转换传参
三、Feign原理
1.将Feign接口代理类注入到Spring容器中
@EnableFeignClients注解开启Feign扫描,先调用FeignClientsRegistrar.registerFeignClients()方法扫描被@FeignClient注解标识的接口生成代理类,再将这些接口和代理类注入到Spring IOC容器中,方便后续被调用。
2、为接口的方法创建RequestTemplate
当consumer调用feign代理类时,代理类会调用SynchronousMethodHandler.invoke()创建RequestTemplate(url,参数)
3、发出请求
代理类会通过RequestTemplate创建Request,然后client(URLConnetct、HttpClient、OkHttp)使用Request发送请求
四、Feign优化
1、开启feign日志
浏览器发起的请求可以通过F12查看请求和响应信息。如果想看微服务中的每个接口,我们可以使用日志配置方式进行详细信息的查看。
Feign虽然提供了日志增强功能,但是默认是不显示任何日志的,不过开发者在调试阶段可以自己配置日志的级别。
Feigin的日志级别如下:
- NONE:默认的,不显示任何日志;
- BASIC:仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了BASIC中定义的信息之外,还是请求和响应的头信息;
- FULL:除了HEADERS定义的信息之外,还有请求和响应的正文及元数据。
在application.yml中设置开启日志,并设置日志级别:
feign: client: config: default: loggerLevel: full logging: level: com.wrs.feign: debug
日志开启效果:
2、feign超时
在service实现层的任意一个方法中添加一个睡眠时间,来模拟连接超时
启动案例,在浏览器中访问这个请求方法,此时在idea控制台,它会报出“连接超时”的错误。
通过下面两种方式来解决连接超时的问题
1、方式一
在配置文件中添加下面属性,设置请求连接的超时时间:
ribbon:
ConnectTimeout: 5000 #请求连接的超时时间
ReadTimeout: 5000 #请求处理的超时时间
2、方式二
feign: client: config: feign-provider: ConnectTimeout: 5000 #请求连接的超时时间 ReadTimeout: 5000 #请求处理的超时时间
通过上边在两种方式在配置文件中分别添加不同的属性,来解决“连接超时”的问题:
3、http连接池
两台服务器建立HTTP
连接的过程涉及到多个数据包的交换,很消耗时间。采用HTTP
连接池可以节约大量的时间提示吞吐量。
Feign的http客户端支持3中框架:HttpURLConnection、HttpClient、OkHttp。
Feign默认是采用java.net.HttpURLConnection的,每次请求都会建立、关闭连接。
添加依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
http连接池在配置文件中是默认开启的,所以无需在配置文件中添加开启属性,只需添加jar依赖才就能实现真正的开启。
在feign.SynchronousMethodHandler()这个方法中debug调试,运行案例就会看到http连接池开启的标志
http连接池关闭:将依赖去除
4、gzip压缩
gzip 介绍:gzip 是一种数据格式,采用用 deflate 算法压缩 data;gzip 是一种流行的文件压缩算法,应用十分广泛,尤其是在 Linux 平台。
gzip 能力:当 Gzip 压缩到一个纯文本文件时,效果是非常明显的,大约可以减少 70%以上的文件大小。
gzip 作用:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的关系。例如 Google就可以通过直接读取 gzip 文件来比普通手工抓取 更快地检索网页。
feign开启gzip步骤:在项目中的yml文件中添加以下内容开启gzip压缩
server:
compression:
enabled: true #开启gzip压缩
开启gzip压缩后的,发送一个请求,查看请求的响应标头,显示出下边这个标志,表示设置成功: