IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 声明式服务调用Feign -> 正文阅读

[Java知识库]声明式服务调用Feign

声明式服务调用Feign

一、Feign介绍

1.什么是feign?

  • feign是spring cloud提供的声明式的http客户端,工作在consumer端
  • feign支持springmvc注解
  • feign集成ribbon也支持负载均衡(restTemplate+ribbon=feign)

2.feign启动器

<dependency>    
  <groupId>org.springframework.cloud</groupId>    
  <artifactId>spring-cloud-starter-openfeign</artifactId>						          
</dependency>

二、Feign入门案例

2.1创建服务提供者feign_provider模块

请添加图片描述

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>com.bjpowernode</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>feign_provider-1</artifactId>

  <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.bjpowernode</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>
    </dependencies>
</project>
  • application.yml
server:
  port: 8090
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.19.132 #注册中心的地址
  application:
    name: feign-provider #注册到nacos的服务名
  • UserController类
package com.bjpowernode.controller;

import com.bjpowernode.pojo.User;
import com.bjpowernode.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/provider")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable Integer id){
        return userService.getUserById(id);
    }
}

  • UserService接口
package com.bjpowernode.service;

import com.bjpowernode.pojo.User;

public interface UserService {
    User getUserById(Integer id);
}

  • UserServiceImpl类
package com.bjpowernode.service;

import com.bjpowernode.pojo.User;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService{

    @Override
    public User getUserById(Integer id){
        return new User(id, "王粪堆-1", 18);
    }
}

  • FeignProviderApp启动类
package com.bjpowernode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient  //注册自己并发现其他服务
public class FeignProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(FeignProviderApp.class, args);
    }
}

2.2创建feign_interface接口模块

请添加图片描述

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>com.bjpowernode</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>feign_interface</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.bjpowernode</groupId>
            <artifactId>springcloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
  • UserFeign接口
package com.bjpowernode.feign;

import com.bjpowernode.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
//问题1:feign的运行原理?
@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserFeign {

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id);//问题2:?必须("id")
}

2.3创建服务消费者feign_consumer模块

请添加图片描述

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>com.bjpowernode</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ribbon_consumer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.bjpowernode</groupId>
            <artifactId>springcloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign接口-->
        <dependency>
            <groupId>com.bjpowernode</groupId>
            <artifactId>feign_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
  • application.yml
server:
  port: 80
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.19.132:8848
  application:
    name: feign-consumer
  • UserController类
package com.bjpowernode.controller;

import com.bjpowernode.feign.UserFeign;
import com.bjpowernode.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("/consumer")
public class UserController {

    @Autowired
    private UserFeign userFeign;//代理类

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable Integer id){
        System.out.println(userFeign.getClass());
        return userFeign.getUserById(id);
    }
}
  • FeignConsumerApp启动类
package com.bjpowernode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient  //注册自己并发现其他服务
@EnableFeignClients  //开启feign注解扫描
public class FeignConsumerApp {

    public static void main(String[] args) {
        SpringApplication.run(FeignConsumerApp.class, args);
    }
}
  • 测试

请添加图片描述

三、Feign原理

3.1 将Feign接口注入到Spring容器中

扫描feign接口生成代理类并交给spring容器管理

@EnableFeignClients开启feign接口扫描:FeignClientsRegistrar.registerFeignClients()扫描被@FeignClient标识的接口生成代理类并交给spring的容器管理

public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		... ... ...
         //扫描feign接口   
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidateComponents = scanner
					.findCandidateComponents(basePackage);
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) 
                                                              candidateComponent;
                      //获得UserFeign的详细信息
					AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
					Assert.isTrue(annotationMetadata.isInterface(),
							"@FeignClient can only be specified on an interface");

					Map<String, Object> attributes = annotationMetadata
							.getAnnotationAttributes(FeignClient.class.getCanonicalName());
					String name = getClientName(attributes);
					registerClientConfiguration(registry, name,
							attributes.get("configuration"));
                      //注入Feign接口到Spring容器中
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}

3.2 RequestTemplate封装请求信息

根据接口上的注解创建RequestTemplate

当controller调用feign代理类时,代理类会调用SynchronousMethodHandler.invoke()创建RequestTemplate(url、requestMethod、body)

    public Object invoke(Object[] argv) throws Throwable {
        //创建一个RequestTemplate
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Retryer retryer = this.retryer.clone();

        while(true) {
            try {
                //发出请求
                return this.executeAndDecode(template);
            } catch (RetryableException var8) {
                ... ... ...
            }
        }
    }
package feign;

public final class RequestTemplate implements Serializable {
    ... ... ... ... ... ...
    private UriTemplate uriTemplate;
    private HttpMethod method;
    private Body body;
    ... ... ... ... ... ...
}    

3.3 发起请求

接着通过RequestTemplate创建Request,然后client(HttpClient、OkHttp、URLConnection)使用Request发送请求

 Object executeAndDecode(RequestTemplate template) throws Throwable {
        //生成请求对象
        Request request = this.targetRequest(template);
        if (this.logLevel != Level.NONE) {
            this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
        }

        long start = System.nanoTime();

        Response response;
        try {
            //发起请求
            response = this.client.execute(request, this.options);
        } catch (IOException var15) {
            ... ... ...

            throw FeignException.errorExecuting(request, var15);
        }
 }       

四、feign接口三种传参方式

1.?传参

? @RequestParam(“”)【拼接?形式的url】

2.restful传参

@PathVariable("")【拼接restful形式的url】

3.pojo传参

? @RequestBody【获取请求体中的json串】

五、Feign请求超时

  • 修改feign_privider:
@Service
public class UserServiceImpl implements UserService {

	@Override
	public User getUser() {
        //模拟网络延迟
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return new User(1,"一直下雨天",18);
	}
}
  • 测试:

请添加图片描述

六、feign优化

6.1开启feign日志

feign虽然提供了日志增强功能,但是默然是不显示任何日志,不过开发者可以自己配置日志级别:

feign的日志级别如下:

NONE:不输出日志
BASIC:输出请求方法及url,响应的状态码及响应时间
HEADERS:输出请求和响应的头信息
FULL:输出请求和响应的请求头,消息体及元数据

在application.yml文件中配置日志级别

feign:
  client:
    config:
      default:
         loggerLevel: full #feign显示日志
logging:
   level:
     com.bjpowernode.feign: debug #log4j的日志级别

6.2 GZIP压缩

  • gzip 是一种数据格式,采用用 deflate 算法压缩 data;gzip 是一种流行的文件 压缩算法,应用十分广泛,尤其是在 Linux 平台。

  • 当 Gzip 压缩到一个纯文本文件时,效果是非常明显的,大约可以减少 70% 以上的文件大小。

  • 网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可 以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏 览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的关系。例如 Google 就可以通过直接读取 gzip 文件来比普通手工抓取 更快地检索网页。

server:
   compression:
       enabled: true #开启浏览器<----->consumer的gzip压缩
feign:
  compression:
     request:
        enabled: true #开启feign<---->provider的gzip压缩
     response:
        enabled: true

请添加图片描述

6.3 http连接池

两台服务器建立HTTP连接的过程涉及到多个数据包的交换,很消耗时间。采用HTTP连接池可以节约大量的时间提示吞吐量。

添加依赖,不需要在application.yml配置开启,默认为开启

<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-httpclient</artifactId>
</dependency>

6.4 feign超时

feign超时优化方式一:
  ribbon:
    ConnectionTimeout: 5000 #请求连接的超时时间
    ReadTimeout: 5000 #请求处理的超时时间
feign超时优化方式二:
  feign:
    client:
      config:
        feign-provider:
           ConnectionTimeout: 5000 #请求连接的超时时间
           ReadTimeout: 5000 #请求处理的超时时间
  • 服务器建立HTTP连接的过程涉及到多个数据包的交换,很消耗时间。采用HTTP连接池可以节约大量的时间提示吞吐量。
  • 添加依赖,不需要在application.yml配置开启,默认为开启
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-httpclient</artifactId>
</dependency>

6.4 feign超时

feign超时优化方式一:
  ribbon:
    ConnectionTimeout: 5000 #请求连接的超时时间
    ReadTimeout: 5000 #请求处理的超时时间
feign超时优化方式二:
  feign:
    client:
      config:
        feign-provider:
           ConnectionTimeout: 5000 #请求连接的超时时间
           ReadTimeout: 5000 #请求处理的超时时间
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:18:51  更:2022-10-17 12:20:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年2日历 -2025/2/1 4:59:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码