微服务间调用——声明式服务调用【Spring Cloud Feign】
目录
- 什么是Feign,能做什么
- 指定Feign的请求(ConnectTimeout),响应超时(ReadTimeOut)
- 使用Gzip进行http网络传输优化Feign
- 使用HttpClient连接池替换Feign的底层实现优化Feign
- Feign的服务接口中传参处理
- 使用feign实现服务调用的demo
什么是Feign [读音:feɪn]
-
Feign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)
-
使用Feign能实现像调用本地方法一样调用远程方法,无需感知操作远程http请求,让Spring Cloud微服务调用像Dubbo一样。
-
Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eurek
-
Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果
-
文档地址:https://cloud.spring.io/spring-cloud-openfeign/reference/html/#spring-cloud-feign
请求超时的配置
请求超时:客户端发起请求,服务端响应并成功建立双向链接的时间。
响应超时:链接创建成功,服务端向返回结果的时间。
在Feign声明式远程调用中,负载均衡还是使用的Ribbon技术。
而Ribbon技术默认的链接超时是1秒,也就是1秒内Application Service没有处理Application Client的请求,且链接请求处理后,
1秒之内没有返回响应,Application Client都会抛出超时异常。
配置优先级
超时策略的使用优先级: 指定服务的超时策略 -> 全局配置的超时策略 -> 默认的超时策略。
全局服务配置
全局服务配置粒度粗糙。商业项目中不同的服务对响应时长的限制也不同,全局服务配置不推荐应用。
# 全局服务配置
# 请求连接的超时时间 默认的时间为1秒
ribbon.ConnectTimeout=5000
# 请求处理的超时时间
ribbon.ReadTimeout=5000
指定服务配置
# 部分服务配置
# 对所有操作请求都进行重试
spring-cloud-feign-appservice.ribbon.OkToRetryOnAllOperations=true
# 对当前实例的重试次数
spring-cloud-feign-appservice.ribbon.MaxAutoRetries=2
# 请求连接的超时时间
spring-cloud-feign-appservice.ribbon.ConnectTimeout=3000
# 请求处理的超时时间
spring-cloud-feign-appservice.ribbon.ReadTimeout=3000
其中:spring-cloud-feign-appservice为调用服务的名称
Feign的通讯优化
GZIP压缩
- 作用:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度,当Gzip压缩到一个纯文本数据时,效果是非常明显的,大约可以减少70%以上的数据大小。
HTTP协议中关于压缩传输的规定
-
第一:客户端向服务器请求头中带有:Accept-Encoding:gzip, deflate 字段,向服务器表示,
客户端支持的压缩格式(gzip或者deflate),如果不发送该消息头,服务器是不会压缩的。 -
第二:服务端在收到请求之后,如果发现请求头中含有Accept-Encoding字段,并且支持该类型的压缩,
就对响应报文压缩之后返回给客户端,并且携带Content-Encoding:gzip消息头,表示响应报文是根据该格式压缩过的。 -
第三:客户端接收到响应之后,先判断是否有Content-Encoding消息头,如果有,按该格式解压报文。否则按正常报文处理。
在Feign技术中应用GZIP压缩
在Spring Cloud微服务体系中,一次请求的完整流程如下:
只配置Feign请求-应答的GZIP压缩
这里只开启Feign请求-应答过程中的GZIP,也就是浏览器-Application Client之间的请求应答不开启GZIP压缩。
在全局配置文件中,使用下述配置来实现Feign请求-应答的GZIP压缩
# feign gzip
# 开启请求GZIP
feign.compression.request.enabled=true
# 开启响应GZIP
feign.compression.response.enabled=true
# 设置支持GZIP压缩的MIME类型,即请求/响应类型。
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 配置启动压缩数据的最小阀值,单位字节。默认为2048
feign.compression.request.min-request-size=512
配置全局的GZIP压缩
在全局配置文件中配置下述内容,来开启所有请求-应答中的GZIP压缩,这里使用的是Spring Boot中的GZIP技术。
在Spring Boot中已经集成了GZIP压缩技术,并对所有的请求-应答实现GZIP数据压缩。
Spring Cloud中已经集成了Spring Boot技术,所以在配置文件中可以开启Spring Boot中的GZIP压缩技术,对完整流程中与当前节点(Application Client)所有相关的请求-应答开启GZIP压缩。
# spring boot gzip
# 开启Spring Boot GZIP压缩
server.compression.enabled=true
# 设置支持GZIP压缩的MIME类型,即请求/响应类型。
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain
HttpClient客户端替换及HTTP连接池
两台服务器建立HTTP连接的过程是很复杂的一个过程,涉及到多个数据包的交换,并且也很耗时间。HTTP连接需要的3次握手4次挥手开销很大,这一开销对于大量的比较小的HTTP消息来说更大。
那么如何来优化HTTP连接性能?我们可以采用HTTP连接池来提升性能,连接池可以节约大量的3次握手4次挥手的时间,这样能大大提升吞吐率。
- feign默认使用的是jdk提供的HttpClient客户端技术(HttpUrlConnection)
HttpClient相比传统JDK自带的HttpURLConnection,它封装了访问http的请求头,参数,内容体,响应等等;
它不仅使客户端发送HTTP请求变得容易,而且也方便了开发人员测试接口(基于Http协议的),
即提高了开发的效率,也方便提高代码的健壮性;另外高并发大量的请求网络的时候,还是用“HTTP连接池”提升吞吐量。
实现步骤
资源依赖:
Feign技术发起请求的位置是Application Client端,下述依赖只需要在Application Client所在工程中添加即可。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
修改全局配置文件:
# 开启feign中的HTTPClient底层应用
feign.httpclient.enabled=true
提供连接池配置类:
@Configuration
public class HttpClientConfiguration {
@Bean
public HttpClient httpClient(){
System.out.println("init feign httpclient configuration " );
// 生成默认请求配置
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
// 超时时间
requestConfigBuilder.setSocketTimeout(5 * 1000);
// 连接时间
requestConfigBuilder.setConnectTimeout(5 * 1000);
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
// 连接池配置
// 长连接保持30秒
final PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
// 总连接数
pollingConnectionManager.setMaxTotal(5000);
// 同路由的并发数
pollingConnectionManager.setDefaultMaxPerRoute(100);
// httpclient 配置
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// 保持长连接配置,需要在头添加Keep-Alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
httpClientBuilder.setConnectionManager(pollingConnectionManager);
httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
HttpClient client = httpClientBuilder.build();
// 启动定时器,定时回收过期的连接
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
pollingConnectionManager.closeExpiredConnections();
pollingConnectionManager.closeIdleConnections(5, TimeUnit.SECONDS);
}
}, 10 * 1000, 5 * 1000);
System.out.println("===== Apache httpclient 初始化连接池===");
return client;
}
}
当使用HttpClient技术作为Feign的底层HTTP技术应用时,使用GET请求方式请求头传递自定义类型对象是可行的,只要在服务标准对象中定义的方法参数上增加注解@RequestBody即可处理。
应用Feign
-
在使用Feign技术开发Spring Cloud微服务时,需要先抽取要注册发布的服务标准,将这套标准通过接口的形式定义出来。
-
在Application Service端开发中,依赖抽取的服务标准接口工程,并对接口给予实现。
-
在Application Client端开发中,依赖抽取的服务标准接口工程,并应用接口信息和Feign技术,实现远程服务的调用。
Feign的接口传参处理
在Feign处理远程服务调用时,传递参数是通过HTTP协议传递的,参数存在的位置是请求头或请求体中。
请求头传递的参数必须依赖@RequestParam注解来处理请求参数,请求体传递的参数必须依赖@RequestBody注解来处理请求参数。
处理请求头传参
使用请求头传递参数时,定义的服务标准接口中,必须使用@RequestParam注解来描述方法参数,且注解属性value/name必须指定,代表从请求头中获取的请求参数命名是什么。
在默认环境中,使用请求头传递参数时,Application Service中的控制器无法使用SpringMVC中的自动对象封装能力。
只能处理简单数据类型。如:数学类型,字符串类型,数组类型等。无法处理自定义对象类型。
处理请求体传参
使用请求体传递参数时,定义的服务标准接口中,必须使用@RequestBody注解来描述方法参数,因为Feign技术发起的POST请求,请求参数是使用JSON字符串来传递的,且form表单类型为RAW。
使用请求体传递参数时,Application Service中的控制器必须使用@RequestBody注解来描述方法参数,且RAW类型的form表单上传的是一个文本内容,只能转换为唯一的一个参数。
如果使用POST方式提交请求,并传递多个普通类型的参数时,Feign不会通过请求体传递参数,是通过请求头传递的参数。
也就是请求路径为 : http://applicationserver:port/url?paramName=paramValue
实现步骤
创建服务标准工程
这个工程的定义主要是为了解决feign service和feign client共享接口和DTO的。
添加pom依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.16.RELEASE</version>
</parent>
<groupId>com.ws</groupId>
<artifactId>spring-cloud-eureka-server</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR4</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>
<!-- spring cloud 默认配置启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- spring cloud Eureka Server 启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
定义服务接口
定义的服务接口和普通的服务接口没有太大的区别,但是为了让Feign技术可以识别到服务的访问URL,
需要使用SpringMVC注解@RequestMapping来描述接口中定义的方法,代表方法对外提供服务时监听的URL路径是什么。
/**
* 微服务标准。
* 是Application Service要提供的服务的标准。
* 也是Application Client要调用远程服务的标准。
* 就是一个普通的接口。
*/
public interface FirstFeignService {
/**
* 测试GET请求的方法。
* 请求不传递任何的参数。
* 请求地址是 - /testFeign -> http://ip:port/testFeign
* @return
*/
@RequestMapping(value="/testFeign", method=RequestMethod.GET)
public List<String> testFeign();
/**
* 测试GET请求传递一个普通的参数。 /get?id=xxx
* 在为Feign定义服务标准接口的时候,处理请求参数的方法参数,必须使用@RequestParam注解描述。
* 且,无论方法参数名和请求参数名是否一致,都需要定义@RequestParam注解的value/name属性。
* @return
*/
@RequestMapping(value="/get", method=RequestMethod.GET)
public FeignTestPOJO getById(@RequestParam(value="id") Long id);
/**
* 测试使用POST请求传递一个普通参数
* 在Feign技术中,默认的发起POST请求的时候,请求的参数,都是在请求体中使用JSON数据传递的。
* 不是name=value对传递的。
* 必须使用@RequestBody注解来解析请求体中的数据。
*
* 如果使用POST方式发起请求,传递多个普通参数,是使用请求头传递的参数。可以使用@RequestParam注解来处理请求参数。
* POST请求的请求体类型还是application/json。feign会通过请求头传递多个请求参数: /xxx?a=xxx&b=xxx&c=xxx
* @return
*/
@RequestMapping(value="/get", method=RequestMethod.POST)
public FeignTestPOJO getByIdWithPOST(@RequestBody Long id);
/**
* 使用GET请求传递多个普通参数。 /add?id=xxx&name=xxx
* 必须使用@RequestParam注解处理请求参数。
* @return
*/
@RequestMapping(value="/add", method=RequestMethod.GET)
public FeignTestPOJO add(@RequestParam("id") Long id, @RequestParam("name") String name);
/**
* 错误案例
* 使用GET请求传递特殊参数。自定义类型的参数。
* 在Feign发起的默认的请求中,GET请求方式不能传递自定义类型数据。只能通过POST请求传递。
* @return
*/
@RequestMapping(value="/addWithGET", method=RequestMethod.GET)
public FeignTestPOJO add(@RequestBody FeignTestPOJO pojo);
/**
* 使用POST请求传递特殊参数。自定义类型的参数。
* 默认环境中,只要是Feign发起的POST请求,请求参数都是JSON数据。
* 必须使用@RequestBody处理。
* @return
*/
@RequestMapping(value="/addWithPOST", method=RequestMethod.POST)
public FeignTestPOJO addWithPOST(@RequestBody FeignTestPOJO pojo);
}
定义DTO
public class FeignTestPOJO {
private Long id;
private String name;
public FeignTestPOJO() {
super();
}
public FeignTestPOJO(Long id, String name) {
super();
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
创建application service (provider)
pom配置
配置pom引入接口服务工程。
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.16.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>spring-cloud-feign-appservice</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- web启动器。 springmvc相关内容 -->
<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>
<!-- spring cloud 默认配置启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- spring cloud Eureka Client 启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 自定义的服务标准(接口)工程。 -->
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>spring-cloud-feign-serviceapi</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
定义一个Controller实现服务接口
/**
* 自定义的服务控制器
* 对外提供服务的Application Service。
* 不能随便的定义服务了。如果想让Application Client可以通过Feign技术访问当前类型提供的服务,
* 则必须遵循服务标准。
*/
@RestController
public class TestFeignAppServiceController implements FirstFeignService {
/**
* 因为当前的方法都是实现接口FirstFeignService中的方法。
* 而在接口中,已经将请求URL和方法耦合到一起了。
* 所以在当前的控制器中,不能重复定义@RequestMapping来约束请求URL。
*/
@Override
public List<String> testFeign() {
List<String> result = new ArrayList<>();
result.add("test feign");
result.add("this is first spring cloud with feign");
return result;
}
@Override
public FeignTestPOJO getById(Long id) {
return new FeignTestPOJO(id, "getById");
}
/**
* 如果方法参数是处理POST请求的JSON数据的。
* 那么还是需要定义@RequestBody注解来描述方法参数的。
*/
@Override
public FeignTestPOJO getByIdWithPOST(@RequestBody Long id) {
return new FeignTestPOJO(id, "getByIdWithPOST");
}
@Override
public FeignTestPOJO add(Long id, String name) {
System.out.println( "add(Long id, String name)" );
return new FeignTestPOJO(id, name);
}
/**
* 在默认的情况下,Feign不能通过GET请求传递自定义类型的请求参数。
*/
@Override
public FeignTestPOJO add(@RequestBody FeignTestPOJO pojo) {
System.out.println( "add(@RequestBody FeignTestPOJO pojo)" );
return pojo;
}
@Override
public FeignTestPOJO addWithPOST(@RequestBody FeignTestPOJO pojo) {
System.out.println( "addWithPOST(@RequestBody FeignTestPOJO pojo)" );
return pojo;
}
}
启动类配置
@EnableEurekaClient
@SpringBootApplication
public class FeignApplicationServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplicationServiceApplication.class, args);
}
}
创建application client
pom配置
引入服务标准工程:pring-cloud-feign-serviceapi
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.16.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>spring-cloud-feign-appclient</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR4</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>
<!-- spring cloud 默认配置启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- spring cloud Eureka Client 启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- feign启动器。封装了所有的feign相关资源的jar包。提供的是默认环境。
feign技术在请求远程服务的时候,依托于http协议。
默认底层使用JDK提供的HttpUrlConnection来实现http远程访问的。
httpurlconnection技术不支持http连接池。所以效率上较低。
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- 服务标准工程。 -->
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>spring-cloud-feign-serviceapi</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
定义接口继承服务标准工程中定义的服务接口
为这个接口添加一个注解:@FeignClient 并指定要调用的application service的名字(也就是application service全局配置文件中的spring.application.name属性值)
mport org.springframework.cloud.netflix.feign.FeignClient;
import com.bjsxt.api.service.FirstFeignService;
/**
* 本地接口,继承服务标准接口。
* 在接口上增加注解@FeignClient,代表当前接口是一个Feign技术中的客户端。
* 需要发起远程的http请求。
* 注解有属性name - 代表当前的FeignClient在请求application service的时候,是调用哪一个服务?
* 所谓的哪一个服务,就是application service全局配置文件中的spring.application.name属性值。
*/
@FeignClient(name="test-feign-application-service")
public interface FirstClientFeignService extends FirstFeignService {
}
这样一定义feign就会帮助我们生成一个application service中服务实现类的代理对象,我们只需要在想使用这个服务的地方注入即可。
引用feign服务
/**
* Application Client中的控制器。是和用户直接交互的控制器。
* 像平时开发代码一样。调用本地的一个service接口。通过service接口远程访问Application Service。
*/
@RestController
public class TestFeignAppClientController {
/**
* 本地定义的服务接口。用于实现远程调用application service的接口。
*/
@Autowired
private FirstClientFeignService service;
/**
* 无参
* @return
*/
@GetMapping("/testFeign")
public List<String> testFeign(){
System.out.println(this.service.getClass().getName());
return this.service.testFeign();
}
/**
* 一个参数,调用远程服务的时候,发起的请求是GET请求
* @return
*/
@GetMapping("/get/{id}")
public FeignTestPOJO getById(@PathVariable("id") Long id){
return this.service.getById(id);
}
/**
* 一个参数,调用远程服务的时候,发起的请求是POST请求
* @return
*/
@GetMapping("/get")
public FeignTestPOJO getByIdWithPOST(Long id){
return this.service.getByIdWithPOST(id);
}
/**
* 多个参数,调用远程服务的时候,发起的请求是GET请求
* @return
*/
@GetMapping("/add/{id}/{name}")
public FeignTestPOJO add(@PathVariable("id") Long id, @PathVariable("name") String name){
return this.service.add(id, name);
}
/**
* 自定义类型参数,调用远程服务的时候,发起的请求是POST请求
* feign技术远程访问application service的时候,默认情况下GET请求不能传递自定义类型参数
* @return
*/
@GetMapping("/add")
public FeignTestPOJO add(FeignTestPOJO pojo){
// return this.service.add(pojo);
return this.service.addWithPOST(pojo);
}
}