深入Feign讲解例子

在我的前一篇文章中已经讲解了什么是Feign,他的作用有什么,还有一个简单的Feign例子。 声明式服务调用Feign

这篇文章主要讲解Feign的复杂多参数情况、GZIP、连接池、日志情况和负载均衡。

我的api和product与上一篇文章中一样,没有什么变化。大家可以参考上一篇文章中的api和product,我们在这里为了减少重复的代码和页面,我只讲consumer中的需要修改的地方。

1、处理复杂参数

目录结构:
在这里插入图片描述
加入依赖:

<dependency>
			<groupId>${project.parent.groupId}</groupId>
			<artifactId>e-book-product-api</artifactId>
			<version>${project.parent.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
123456789

ProductController中的代码:

@RestController
public class ProductController {
	@Autowired
	private ProductService productService;
	@RequestMapping(value="list",method=RequestMethod.GET)
	public List<Product> listProduct(){
		List<Product> list= this.productService.listProduct();
		return list;
	}
	//一个参数
	@RequestMapping(value="get",method=RequestMethod.GET)
	public Product getProduct(@RequestParam("id") Integer id) {
		return this.productService.getProduct(id);
	}
	//------------------------多参数----------------------
	//不能这么写,因为feign会自动转换为post
	@RequestMapping(value="get1",method=RequestMethod.GET)
	public Product getProduct1(Product obj) {
		return this.productService.getProduct1(obj);
	}
	@RequestMapping(value="get2",method=RequestMethod.GET)
	public Product getProduct2(@RequestParam("id") Integer id,@RequestParam("name") String name) {
		return this.productService.getProduct2(id,name);
	}
	//------------------------POST-------------------------
	@RequestMapping(value="add",method=RequestMethod.GET)
	public Product addProduct() {
		Product obj = new Product(2,"test5");
		return this.productService.addProduct(obj);
	}
}
12345678910111213141516171819202122232425262728293031

ProductService代码和上一篇一样。
在上面的接口中,我们定义了单个参数,多个参数,POST请求的这几种情况,在实际开发中差不多也是这几种情况。然后我们需要注意的一个地方就是多参数部分中,第一个是错误的,因为feign会自动转换为post。我们只能在参数中接收2个参数才正确,但是后面有一种方法可以解决这种问题。
第一种方法测试,报错信息:
在这里插入图片描述
第二种方法测试:
在这里插入图片描述
然后其他的都很简单,需要注意的就只有这个地方。

2、Feign基于Gzip压缩提升通信速度

关于gzip的介绍:
在这里插入图片描述
加入依赖:

<dependency>
			<groupId>${project.parent.groupId}</groupId>
			<artifactId>e-book-product-api</artifactId>
			<version>${project.parent.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
123456789

目录结构:
在这里插入图片描述
ProductController代码:

@RestController
public class ProductController {
	@Autowired
	private ProductService productService;
@RequestMapping(value="list",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	@RequestMapping(value="list",method=RequestMethod.GET)
	public List<Product> listProduct(){
		List<Product> list= this.productService.listProduct();
		System.out.println(list+"dddddddddd");
		return list;
	}
}
123456789101112

ProductService代码和上一篇一样
配置文件加入代码:

##默认是hostname 注册,改成IP 注册
#eureka.instance.perferIpAddress=true
#
##-----------------------------gzip
## 配置请求GZIP压缩
#feign.compression.request.enabled=true
## 配置响应GZIP压缩
#feign.compression.response.enabled=true
#
## 配置压缩支持的MIME TYPE
#feign.compression.request.mime-types=text/xml,application/xml,application/json
## 配置压缩数据大小的下限
#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,text/plain
1234567891011121314151617

这里注释的代码可以不要,只要最后的两行代码,因为启用压缩过后就包含了上面的步骤。
这里需要的注意的是,如果你的页面请求接口返回在页面上的数据是xml的时候,你需要将它变为json格式才行,不然就不会成功
这里有两个解决的方法:
1. com.fasterxml.jackson.dataformat jackson-dataformat-xml
2.@RequestMapping(value="list",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
加入produces=MediaType.APPLICATION_JSON_UTF8_VALUE
当你访问接口时,看见有这两行说明就成功了。
在这里插入图片描述
小结一下gzip主要就是加入一个依赖,然后返回的时候不要是xml,而是json才可以。gzip可以很好的减少网页打开的速度。

3.基于连接池,提升吞吐量

介绍:
在这里插入图片描述
加入依赖,原来的那连个还是要加,而且还添加了另外的两个httpclient的依赖:

<!-- 使用Apache HttpClient替换Feign原生httpclient -->
<dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
		<dependency>
		    <groupId>com.netflix.feign</groupId>
		    <artifactId>feign-httpclient</artifactId>
		    <version>8.18.0</version>
</dependency>
1234567891011

pom中的代码:

#启动httpclient
feign.httpclient.enabled=true
12

目录结构:
在这里插入图片描述
ProductController代码:

@RestController
public class ProductController {
	@Autowired
	private ProductService productService;
	@RequestMapping(value="list",method=RequestMethod.GET)
	public List<Product> listProduct(){
		List<Product> list= this.productService.listProduct();
		return list;
	}
	//一个参数
	@RequestMapping(value="get",method=RequestMethod.GET)
	public Product getProduct(@RequestParam("id") Integer id) {
		return this.productService.getProduct(id);
	}
	//------------------------多参数----------------------
	//不能这么写,因为feign会自动转换为post,采用httpclient解决了feign自动转post的问题
	@RequestMapping(value="get1",method=RequestMethod.GET)
	public Product getProduct1(Product obj) {
		return this.productService.getProduct1(obj);
	}
	@RequestMapping(value="get2",method=RequestMethod.GET)
	public Product getProduct2(@RequestParam("id") Integer id,@RequestParam("name") String name) {
		return this.productService.getProduct2(id,name);
	}
	//------------------------POST-------------------------
	@RequestMapping(value="add",method=RequestMethod.GET)
	public Product addProduct() {
		Product obj = new Product(2,"test5");
		return this.productService.addProduct(obj);
	}
}
12345678910111213141516171819202122232425262728293031

加入httpclient过后我们就可以解决上面遗留的问题了,解决了feign自动转换为post的问题。
测试:
在这里插入图片描述
现在测试接口就成功了。

4.日志记录每个接口URL,状态码和耗时信息

目录结构:
在这里插入图片描述
依赖包还是加入api的那连个依赖。
主要的就是怎么加入logs这个包。
ProductController代码:

@RestController
public class ProductController {
	@Autowired
	private ProductService productService;
	@RequestMapping(value="list",method=RequestMethod.GET)
	public List<Product> listProduct(){
		List<Product> list= this.productService.listProduct();  
		return list;
	}
}
12345678910

LogConfiguration代码:

@Configuration
public class LogConfiguration {
	@Bean
	public Logger.Level feignLoggerLevel() { 
//		NONE, 不记录任何信息,默认值。
//		BASIC, 记录请求方法、请求URL、状态码和用时。
//		HEADERS, 在BASIC的基础上再记录一些常用信息。	
//		FULL: 记录请求和响应报文的全部内容。
		return Logger.Level.FULL;
	}
}
1234567891011

ProductService代码,这里与上面的那些有点不一样:

@FeignClient(name="e-book-product",configuration = LogConfiguration.class)
public interface ProductService extends ProductFacade{
}
123

这里加入了configuration = LogConfiguration.class其实就是上面的那个类。
pom中加入一行代码:

logging.level.com.me.book.consumer.service.ProductService: DEBUG
1

其中com.me.book.consumer.service.ProductService是我新创建的那个logs那个类的全路径。现在就添加完了。
测试结果:
在这里插入图片描述
在这里插入图片描述

5.Feign负载均衡

这个例子与简单例子相似,只不过在pom中加入了这几行代码,然后在product中改变了一下代码。
pom中的加入的代码:

#全局配置
## 请求连接的超时时间
#ribbon.ConnectTimeout=5000
## 请求处理的超时时间
#ribbon.ReadTimeout=5000
#局部配置
# 对所有操作请求都进行重试
e-book-product.ribbon.OkToRetryOnAllOperations=true
# 对当前实例的重试次数
e-book-product.ribbon.MaxAutoRetries=2
# 切换实例的重试次数
e-book-product.ribbon.MaxAutoRetriesNextServer=0
# 请求连接的超时时间
e-book-product.ribbon.ConnectTimeout=3000
# 请求处理的超时时间
e-book-product.ribbon.ReadTimeout=3000
# 指定具体的服务实例清单
#e-book-product.ribbon.listOfServers= 
123456789101112131415161718

在product中的ProductFacadeImpl的listProduct方法改变了一下:

@RequestMapping(value="list",method=RequestMethod.GET)
	public List<Product> listProduct(){
		System.out.println("########################");
//		try {
//			Thread.sleep(6*1000);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		List<Product> list= new  ArrayList<Product>();
		list.add(new Product(1,"test1无的放矢付撒发付过过过过过过过过"));
		list.add(new Product(2,"test2无的放矢付撒奥过过过过过过过过"));
		list.add(new Product(3,"test3无的放矢付付撒奥过过过过过过过过"));
		return list;
	}
123456789101112131415

加入了try catch代码。我们设置的时间是连接3秒,而listProduct中延迟6秒,所以就会请求超时。而且我们可以设置重新连接的次数,为2次。
测试结果,连接超时:
在这里插入图片描述


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!