Feign是一種聲明式、模板化的HTTP客戶端(僅在consumer中使用)。php
聲明式調用就像調用本地方法同樣調用遠程方法,無感知遠程HTTP請求。html
1.SpringCloud的聲明式調用,能夠作到使用HTTP請求遠程服務時就像調用本地方法同樣的體驗,開發者徹底感知不到這是遠程方法。更感知不到這是一個HTTP請求。java
2.它像Dubbo同樣,consumr直接調用接口方法調用provider,而不須要經過常規的Http Client構造請求再解析返回數據。web
3.它解決了讓開發者調用遠程接口就跟調用本地方法同樣,無需關注與遠程的交互細節,更無需關注分佈式環境開發。算法
實現電商平臺的基本操做spring
<?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>
複製代碼
/** * 描述: 商品接口 */
@RequestMapping("/product")
public interface ProductService {
//查詢全部商品
@RequestMapping(value = "/findAll", method = RequestMethod.GET)
public List<Product> findAll();
}
複製代碼
/** * 描述: 商品實體 */
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;
}
}
複製代碼
<?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>
複製代碼
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/
複製代碼
/** * 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;
}
}
複製代碼
@EnableEurekaClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
複製代碼
<?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>
複製代碼
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/
複製代碼
/** * 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();
}
}
複製代碼
//指定實現該接口的服務
@FeignClient(name = "ego-product-provider")
public interface ProductConsumerService extends ProductService {
}
複製代碼
//添加以下兩個註解開啓對feign的支持
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
複製代碼
//根據商品id查詢商品
@RequestMapping(value = "/getProductById", method = RequestMethod.GET)
//RequestParam必須指定參數
public Product getProductById(@RequestParam("id") Integer id);
複製代碼
@Override
public Product getProductById(Integer id) {
return new Product(id, "SpringCloud");
}
複製代碼
/** * Consumer中根據商品id查詢商品 */
@RequestMapping(value = "/get", method = RequestMethod.GET)
public Product getProduct(@RequestParam("id") Integer id){
return consumerService.getProductById(id);
}
複製代碼
//添加商品,傳遞多個參數,get方式
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Product addProduct(@RequestParam("id") Integer id, @RequestParam("name") String name);
複製代碼
@Override
public Product addProduct(Integer id, String name) {
return new Product(id, name);
}
複製代碼
/** * 商品添加,傳遞多個參數,get方式 */
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Product addProduct(Product product){
return consumerService.addProduct(product.getId(), product.getName());
}
複製代碼
//添加商品,傳遞多個參數,post方式
@RequestMapping(value = "/add2", method = RequestMethod.POST)
public Product addProduct2(@RequestBody Product product);
複製代碼
@Override
public Product addProduct2(@RequestBody Product product) {
return product;
}
複製代碼
/** * 商品添加,傳遞多個參數,post方式 */
@RequestMapping(value = "/add2", method = RequestMethod.GET)
public Product addProduct2(Product product){
return consumerService.addProduct2(product);
}
複製代碼
gzip原理:gzip是一種數據格式,採用deflate算法壓縮數據,gzip是一種流行的文件壓縮算法,應用十分普遍,尤爲是在Linux平臺。apache
gzip能力:當gzip壓縮到一個純文本文件時效果是很是明顯的,大約能夠減小70%以上的文件大小。json
gzip的做用:網絡數據通過壓縮後也就較低了網絡傳輸的字節數,最明顯的就是能夠提升網頁加載的速度。網頁加載速度加快的好處不言而喻,除了節省流量、改善用戶的瀏覽體驗外,另外一個潛在的好處就是gzip與搜索引擎的提取工具備着更好的關係。例如Google就能夠直接經過讀取gzip文件來比普通手工抓取更快的檢索網頁。瀏覽器
第一:客戶端向服務器請求中帶有:Accept-Encoding:gzip,deflate字段,向服務器表示,客戶端支持的壓縮格式(gzip或者deflate),若是不發送該消息頭,服務器是不會壓縮的。性能優化
第二:服務端在收到請求以後,若是發現請求頭中含有Accept-Encoding字段,而且支持該類型的壓縮,就對響應報文壓縮以後返回給客戶端。而且攜帶Content-Encoding:gzip消息頭,表示響應報文是根據該格式壓縮過的。
第三:客戶端接收請求以後,先判斷是否有Content-Encoding:消息頭,若是有,按改格式解壓報文,不然按正常報文處理。
#配置請求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
複製代碼
爲何http鏈接池能提升性能
a.兩臺服務器創建http鏈接的過程是很複雜的過程,涉及到多個數據包的交換,而且也很消耗時間
b.Http鏈接須要三次握手四次揮手,開銷很大。這樣的開銷對於請求比較多但信息量又比較小的請求開銷更大。
a.若是咱們直接採用http鏈接池,節約了大量三次握手四次揮手的時間,這樣能大大提高吞吐量。
b.feign的http客戶端支持3種框架:HttpURLConnection、HttpClient、okhttp,默認是HttpURLConnection。
c.傳統的HttpURLConnection是JDK自帶的,並不支持鏈接池,若是要實現鏈接池的機制。還須要本身來管理鏈接對象。對於網絡請求這種底層相對複雜的操做,若是有可用的其餘方案,也沒有必要本身去管理鏈接對象。
d.HttpClient相比於JDK自帶的HttpURLConnection,它封裝了訪問http的請求頭、參數、內容體、響應等等。它不只使發送http請求變得容易,並且也方便開發人員測試接口(基於HTTP協議的),即提升了開發的效率,也方便提升代碼的健壯性,另外高併發大量的請求的時候,仍是用鏈接池提升吞吐量。
<!--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>
複製代碼
#啓用httpclient
feign.httpclient.enabled=true
複製代碼
注意:若是使用HttpClient做爲Feign做爲Feign的客戶端工具,那麼在定義接口上的註解時須要注意,若是傳遞的是一個自定義對象(對象會使用json類型來傳遞),須要添加指定類型
/** * 描述: 商品接口 */
@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);
}
複製代碼
將輸出日誌級別設置爲DEBUG
<!-- 日誌輸出級別 -->
<root level="DEBUG">
<appender-ref ref="Stdout" />
<appender-ref ref="RollingFile" />
</root>
複製代碼
//添加以下兩個註解開啓對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的負載均衡底層用的就是Ribbon
#全局配置
#請求鏈接的超時時間,默認爲1000ms
ribbon.ConnectTimeout=5000
#處理請求的超時時間
ribbon.ReadTimeout=5000
複製代碼
#局部配置
#對全部操做請求都進行重試
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
複製代碼