1. Что такое притворство
Feign — это декларативный шаблонный протокол HTTP.клиент(Используется только в потребителе).
Во-вторых, что такое декларативный подход, какую роль он играет и какую проблему решает?
Декларативные вызовы похожи на вызовысобственный методТо же, что и вызов удаленных методов, не зная об удаленных HTTP-запросах.
1. Декларативный вызов SpringCloud может обеспечить тот же опыт, что и вызов локального метода при использовании HTTP для запроса удаленной службы Разработчик совершенно не подозревает, что этоудаленный метод. ЧетноеНе знаю, что это HTTP-запрос.
2. Как и в случае с Dubbo, потребитель напрямую вызывает метод интерфейса для вызова провайдера без необходимости создавать запрос через обычный Http-клиент и затем анализировать возвращенные данные.
3. Решает проблему, позволяющую разработчикам вызывать удаленные интерфейсы так же, как вызовы локальных методов, не обращая внимания на детали взаимодействия с удаленным, не говоря уже о разработке распределенной среды.
3. Написание вводного кейса для Feign
1. Спрос
Реализовать базовую работу платформы электронной коммерции
2. Дизайн проекта
3. Создаем проект Продукт-Сервис
3.1 Добавить координаты
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.luyi</groupId>
<artifactId>springcloud-ego-product-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-ego-product-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2 Создать сервисный интерфейс
/**
* 描述: 商品接口
*/
@RequestMapping("/product")
public interface ProductService {
//查询所有商品
@RequestMapping(value = "/findAll", method = RequestMethod.GET)
public List<Product> findAll();
}
3.3 Создание класса pojo
/**
* 描述: 商品实体
*/
public class Product {
private Integer id;
private String name;
public Product() {
}
public Product(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4. Создайте поставщика продукта
4.1 Добавление координат
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.luyi</groupId>
<artifactId>springcloud-ego-product-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-ego-product-provider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!--product service-->
<dependency>
<groupId>com.luyi</groupId>
<artifactId>springcloud-ego-product-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.2 Изменить файл конфигурации
spring.application.name=ego-product-provider
server.port=9001
#设置服务注册中心地址,向所有注册中心做注册
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
4.3 Запись контроллера
/**
* Product-Provider服务
*/
@RestController
public class ProductController implements ProductService {
@Override
public List<Product> findAll() {
ArrayList<Product> list = new ArrayList<>();
list.add(new Product(1, "电视"));
list.add(new Product(2, "电脑"));
list.add(new Product(3, "冰箱"));
list.add(new Product(4, "手电筒"));
return list;
}
}
4.4 Напишите класс запуска SpringBoot
@EnableEurekaClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
5. Создайте продукт-потребителя
5.1 Добавление координат
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.luyi</groupId>
<artifactId>springcloud-ego-product-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-ego-product-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!--添加feign的坐标-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!--product service-->
<dependency>
<groupId>com.luyi</groupId>
<artifactId>springcloud-ego-product-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
5.2 Изменить файл конфигурации
spring.application.name=ego-product-consumer
server.port=9002
#设置服务注册中心地址,向所有注册中心做注册
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
5.3 Написание контроллера
/**
* Product-Consumer服务
*/
@RestController
public class ProductController {
@Autowired
private ProductConsumerService consumerService;
/**
* Consumer中查询所有商品的方法
* @return
*/
@RequestMapping(value = "/list", method = RequestMethod.GET)
public List<Product> list(){
return consumerService.findAll();
}
}
5.4 Услуги письма
//指定实现该接口的服务
@FeignClient(name = "ego-product-provider")
public interface ProductConsumerService extends ProductService {
}
5.5 Изменить класс запуска
//添加如下两个注解开启对feign的支持
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
В-четвертых, обработка параметров запроса Feign.
1. Обработка одного параметра
1.1 Измените проект Product-Service и добавьте методы
//根据商品id查询商品
@RequestMapping(value = "/getProductById", method = RequestMethod.GET)
//RequestParam必须指定参数
public Product getProductById(@RequestParam("id") Integer id);
1.2 Изменить поставщика продукта
@Override
public Product getProductById(Integer id) {
return new Product(id, "SpringCloud");
}
1.3 Изменить продукт-потребитель
/**
* Consumer中根据商品id查询商品
*/
@RequestMapping(value = "/get", method = RequestMethod.GET)
public Product getProduct(@RequestParam("id") Integer id){
return consumerService.getProductById(id);
}
2. Метод обработки нескольких параметров 1: Получить метод отправки
2.1 Изменить продукт-услугу
//添加商品,传递多个参数,get方式
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Product addProduct(@RequestParam("id") Integer id, @RequestParam("name") String name);
2.2 Изменить поставщика продукта
@Override
public Product addProduct(Integer id, String name) {
return new Product(id, name);
}
2.3 Изменить продукт-потребитель
/**
* 商品添加,传递多个参数,get方式
*/
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Product addProduct(Product product){
return consumerService.addProduct(product.getId(), product.getName());
}
3. Метод обработки нескольких параметров 2: метод отправки после отправки
3.1 Изменить продукт-услугу
//添加商品,传递多个参数,post方式
@RequestMapping(value = "/add2", method = RequestMethod.POST)
public Product addProduct2(@RequestBody Product product);
3.2 Изменить поставщика продукта
@Override
public Product addProduct2(@RequestBody Product product) {
return product;
}
3.3 Изменить продукт-потребитель
/**
* 商品添加,传递多个参数,post方式
*/
@RequestMapping(value = "/add2", method = RequestMethod.GET)
public Product addProduct2(Product product){
return consumerService.addProduct2(product);
}
Пять, оптимизация производительности Feign
1. Улучшите скорость передачи данных по сети с помощью алгоритма сжатия Gzip.
1.1 Введение в gzip
Принцип gzip: gzip — этоФормат данных, использующий алгоритм deflate для сжатия данных, gzip — это популярный алгоритм сжатия файлов, который широко используется, особенно на платформе Linux.
Возможность gzip: когда gzip сжимает дообычный текстовый файлЭффект очень очевиден, и размер файла можно уменьшить более чем на 70%.
Роль gzip: после сжатия сетевых данныхЭто также уменьшает количество байтов, передаваемых по сети., в первую очередьМожет увеличить скорость загрузки веб-страницы. Преимущества более быстрой загрузки веб-страниц очевидны.Помимо экономии трафика и улучшения просмотра для пользователей, еще одним потенциальным преимуществом является то, что gzip лучше взаимодействует с инструментами извлечения поисковых систем. Например, Google может напрямую извлекать веб-страницы, читая файлы gzip быстрее, чем обычное сканирование вручную.
1.2 Положения о сжатой передаче в протоколе HTTP
Первый: клиент запрашивает сервер с помощью:Принять кодировку: gzip, поле deflate указывает серверу формат сжатия (gzip или deflate), поддерживаемый клиентом.Если заголовок сообщения не отправлен, сервер не будет его сжимать.
Второе: после того, как сервер получит запрос, если он обнаружит, что заголовок запроса содержит поле Accept-Encoding и поддерживает этот тип сжатия, он сжимает ответное сообщение и возвращает его клиенту.И несите заголовок Content-Encoding: gzip, указывающий, что ответное сообщение сжато в соответствии с этим форматом.
Третье: после того, как клиент получает запрос, он сначала определяет, есть лиContent-Encoding: заголовок сообщения, если есть, распаковать пакет в соответствии с измененным форматом, иначе он обрабатывается как обычный пакет.
2. Напишите случай сжатия с поддержкой Gzip
2.1 Создать проект
2.2 Изменить файл конфигурации
- Настройте потребителя только для сжатия запроса и ответа от симуляции до провайдера.
#配置请求GZIP压缩
feign.compression.request.enabled=true
#配置响应GZIP压缩
feign.compression.respinse.enabled=true
#配置压缩支持MIME TYPE
feign.compression.request.mime-types=text/xml,application/xml,application/json
#配置压缩数据大小的最小阈值,默认2048
feign.compression.request.min-request-size=512
- Сжатие запроса к клиентскому браузеру и запроса и ответа потребителя к провайдеру
#-------------spring boot gzip
#是否启用压缩
server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,type/plain
3. Использование пула HTTP-соединений для повышения параллельной пропускной способности Feign.
Почему пул HTTP-соединений повышает производительность
3.1 Фоновый принцип http
А. Процесс установления http-соединения между двумя серверами — очень сложный процесс, включающий обмен несколькими пакетами данных, а также требующий много времени.
b.Http-соединение требует трех рукопожатий и четырех волн, что очень дорого. Такие накладные расходы больше для запросов с большим количеством запросов, но меньшим количеством информации.
3.2 Оптимизация решения
А. Если мы напрямую используем пул соединений http, это экономит много времени для трехэтапных рукопожатий и четырех волн, что может значительно повысить пропускную способность.
http-клиент b.feign поддерживает 3 фреймворка: HttpURLConnection, HttpClient, okhttp, по умолчанию — HttpURLConnection.
c. Традиционный HttpURLConnection поставляется с JDK и не поддерживает пул соединений.Если вы хотите реализовать механизм пула соединений. Вам также необходимо самостоятельно управлять объектами подключения. Для относительно сложной работы сетевого запроса при наличии других доступных решений нет необходимости самостоятельно управлять объектом подключения.
d.HttpClient, по сравнению с собственным HttpURLConnection JDK, инкапсулирует заголовки запросов, параметры, тела контента, ответы и т. д. для доступа к http. Это не только упрощает отправку http-запросов, но и облегчает разработчикам тестирование интерфейса (на основе протокола HTTP), что не только повышает эффективность разработки, но и повышает надежность кода.
4. Измените HTTP-инструмент Feign на HttpClient.
4.1 Создать проект
4.2 Добавление координат
<!--Apache HttpClient替换Feign原生httpURLConnection-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>8.17.0</version>
</dependency>
4.3 Измените файл конфигурации, чтобы включить использование HttpClient
#启用httpclient
feign.httpclient.enabled=true
Примечание: Если вы используете HttpClient as Feign as клиентский инструмент Feign, вам нужно обратить внимание на определение аннотаций на интерфейсе.Если вы передаете пользовательский объект (объект будет передан в формате json), вам нужно добавить указанный тип
4.4 Product-Service
/**
* 描述: 商品接口
*/
@RequestMapping("/product")
public interface ProductService {
//查询所有商品
@RequestMapping(value = "/findAll", method = RequestMethod.GET)
public List<Product> findAll();
//根据商品id查询商品
@RequestMapping(value = "/getProductById", method = RequestMethod.GET)
public Product getProductById(@RequestParam("id") Integer id);
//添加商品,传递多个参数,get方式
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Product addProduct(@RequestParam("id") Integer id, @RequestParam("name") String name);
//----------------------------------HttpClient------------------------------------
//添加商品,传递多个参数,post方式
@RequestMapping(value = "/add2", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public Product addProduct2(@RequestBody Product product);
//使用HttpClient工具添加商品,传递多个参数,基于Get方式
@RequestMapping(value = "/add3", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE)
public Product addProduct3(Product product);
}
6. Просмотрите URL-адрес, код состояния и отнимающую много времени информацию о каждом интерфейсе, записанную в журнале микросервиса.
1. Создайте проект
2. Добавьте файл logback.xml
Установите уровень выходного журнала наDEBUG
<!-- 日志输出级别 -->
<root level="DEBUG">
<appender-ref ref="Stdout" />
<appender-ref ref="RollingFile" />
</root>
3. Добавьте метод в класс запуска
//添加如下两个注解开启对feign的支持
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
/**
* NONE:不记录任何信息,默认值
* BASIC:记录请求url、请求方法、状态码和用时的时候使用
* HEADERS:在BASIC基础上再记录一些常用信息
* FULL:记录请求和响应的所有信息
*/
@Bean
public Logger.Level getLog(){
return Logger.Level.FULL;
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
Семь, настройте время ожидания запроса балансировки нагрузки Feign.
Нижний уровень балансировки нагрузки Feign использует ленту.
1. Измените файл конфигурации и установите время ожидания
1.1 Глобальная конфигурация
#全局配置
#请求连接的超时时间,默认为1000ms
ribbon.ConnectTimeout=5000
#处理请求的超时时间
ribbon.ReadTimeout=5000
1.2 Конфигурация локального тайм-аута на основе имени службы
#局部配置
#对所有操作请求都进行重试
ego-product-provider.ribbon.OkToRetryOnAllOperations=true
#对当前实例的重试次数
ego-product-provider.ribbon.MaxAutoRetries=2
#切换实例的重试次数
ego-product-provider.ribbon.MaxAutoRetriesNextServer=0
#请求连接的超时时间
ego-product-provider.ribbon.ConnectTimeout=3000
#请求处理的超时时间
ego-product-provider.ribbon.ReadTimeout=3000