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
复制代码