Spring Cloud服务调用
OpenFeign
核心api
Spring Cloud Feign
使用RestTemplate
自定义实现服务调用Spring Cloud Feign
源码分析
Spring Cloud服务调用
版本信息
Spring Cloud : Hoxton.SR1
Spring Boot : 2.2.2.RELEASE
Zookeeper : 3.5.6 (注册中心使用)
OpenFeign
核心api
Feign is a Java to HTTP client binder inspired by Retrofit, JAXRS-2.0, and WebSocket
feign.Feign
核心类feign.Contract
服务接口类的注解和值解析feign.Client
调用feign.Retryer
重试feign.codec.Encoder
序列化,对象转成Http
请求feign.codec.Decoder
反序列化,Http
请求转换为对象feign.QueryMapEncoder
查询参数的编码feign.codec.ErrorDecoder
错误信息编码feign.Request
请求参数feign.InvocationHandlerFactory
控制反射方法分派
Spring Cloud Feign
使用
服务端
一个简单的对外提供服务,基于
Zookeeper
注册中心
添加
pom
依赖1
2
3
4
5
6
7
8
9
10
11
12
13
14<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--zookeeper 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>简单的对外提供服务端点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20/**
* 演示服务端点
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/2/7
*/
@RestController
public class EchoController {
@Autowired
private Environment environment;
@GetMapping("/echo")
public String echo(@RequestParam String message) {
// 由于采用的是随机端口,这地方必须采用这个方式获取端口
String port = environment.getProperty("local.server.port");
return "ECHO(" + port + "):" + message;
}
}配置文件
application.yml
1
2
3
4
5
6
7
8spring:
application:
name: feign-server
cloud:
zookeeper:
connect-string: 127.0.0.1:2181
server:
port: 0服务启动程序类
FeignServerApplication
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* Feign 服务端应用
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/2/7
*/
@SpringBootApplication
public class FeignServerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignServerApplication.class, args);
}
}启动服务,根据启动日志查看本地的随机端口,此次端口是
60981
http://127.0.0.1:60981/echo?message=Hello
返回信息ECHO(60981):Hello
客户端
添加
pom
依赖1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--zookeeper 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<!--openfeign 客户端调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>服务提供接口
1
2
3
4
5
6
7
8
9
10
11
12/**
* 服务提供echo服务
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/2/7
*/
@FeignClient("feign-server") //标注是Feign Client
public interface EchoService {
@GetMapping("/echo")
String echo(@RequestParam("message") String message);
}客户端提供服务端点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/**
* 演示服务端点
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/2/7
*/
@RestController
public class EchoController {
@Autowired
private EchoService echoService;
@GetMapping("/echo")
public String echo(String message) {
return this.echoService.echo(message);
}
}配置文件
application.yml
1
2
3
4
5
6
7
8spring:
application:
name: feign-client
cloud:
zookeeper:
connect-string: 127.0.0.1:2181
server:
port: 8090服务启动程序类
FeignClientApplication
1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* Feign 客户端服务
*
* @author FelixFly <chenglinxu@yeah.net>
* @date 2020/2/7
*/
@SpringBootApplication
@EnableFeignClients(clients = EchoService.class) //启用Feign Client
public class FeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(FeignClientApplication.class, args);
}
}启动服务,
http://localhost:8090/echo?message=hello
返回信息ECHO(60981):hello
RestTemplate
自定义实现服务调用
自定义客户端调用注解
1 |
|
自定义客户端调用服务
1 |
|
自定义客户端启用注解
1 |
|
导入RestFeignClientsRegistrar
1 |
|
动态代理调用RestFeignClientInvocationHandler
1 |
|
启动添加启用注解
1 |
|
演示服务端点
1 |
|
启动服务,
http://localhost:8090/rest/echo?message=hello
返回信息ECHO(60981):hello
Spring Cloud Feign
源码分析
@EnableFeignClients
分析
1 |
|
导入了FeignClientsRegistrar
1 |
|
注册了FeignClientFactoryBean
1 |
|
构建了一个Feign调用,客户端有两种LoadBalancerFeignClient
以及FeignBlockingLoadBalancerClient
,
配置属性FeignClientProperties
OpenFeign
核心api
在Spring Cloud中的扩展
org.springframework.cloud.openfeign.FeignClientsConfiguration
默认的配置类
feign.Contract
服务接口类的注解和值解析org.springframework.cloud.openfeign.support.SpringMvcContract
支持
Spring MVC
的注解,比如@RequestMapping
、@PathVariable
等等参数注解处理核心接口:
org.springframework.cloud.openfeign.AnnotatedParameterProcessorr
@PathVariable
PathVariableParameterProcessor
@RequestParam
RequestParamParameterProcessor
@RequestHeader
RequestHeaderParameterProcessor
@SpringQueryMap
QueryMapParameterProcessor
feign.Client
调用org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient
Ribbon客户端调用org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient
阻塞的Feign客户端,Spring Cloud LoadBalanced
实现
feign.Retryer
重试Retryer.NEVER_RETRY
不进行重试
feign.codec.Encoder
序列化,对象转成Http
请求new SpringEncoder(this.messageConverters)
普通的反序列化new PageableSpringEncoder(new SpringEncoder(this.messageConverters))
带有分页参数的反序列化
从上可以得知,这个序列是通过
HttpMessageConverter
组合去处理的feign.codec.Decoder
反序列化,Http
请求转换为对象new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)))
从上可以得知,这个反序列是通过
HttpMessageConverter
组合去处理的