远程过程调⽤用(RPC)
一个计算机通信协议。该协议允许运⾏行行于⼀一台计算机的程序调⽤用另⼀一台计算机的⼦子程序,⽽而程序员 ⽆无需额外地为这个交互作⽤用编程。如果涉及的软件采⽤用⾯面向对象编程,那么远程过程调⽤用亦可称作 远程调⽤用或远程⽅方法调⽤用
- 例如
- Java RMI( ⼆二进制协议)
- WebServices(⽂文本协议)
- 消息传递
RPC 是⼀一种请求-响应协议,⼀一次 RPC在客户端初始化,再由客户端将请求消息传递到远程的服 务器器,执⾏行行指定的带有参数的过程。经过远程服务器器执⾏行行过程后,将结果作为响应内容返回到客 户端。 - 存根(Stub)
在⼀一次分布式计算 RPC 中,客户端和服务器器转化参数的⼀一段代码。 由于存根的参数转化,RPC 执⾏行行过程如同本地执⾏行行函数调⽤用。存根必须在客户端和服务器器两端均装载,并且保持兼容
Spring Cloud Feign
-
依赖
- org.springframework.cloud:spring-cloud-starter-feign
-
激活
- @EnableFeignClients
-
申明
- @FeignClient
-
默认组件
- Decoder/Encoder : ResponseEntityDecoder / SpringEncoder
- Logger : Slf4jLogger
- Contract : SpringMvcContract
- Feign.Builder : HystrixFeign.Builder
- Client : LoadBalancerFeignClient(Ribbon 激活的话)
Feign、Spring Cloud Open Feign、JAX-RS、Spring Web MVC 注解驱 动特性
REST 框架 | 使用场景 | 请求映射注解 | 请求参数 |
---|---|---|---|
Feign | 客户端声明 | @RequestLine | @Param |
Spring Cloud Open Feign | 客户端声明 | @RequestMapping | @RequestParam |
JAX-RS | 客户端声明、服务端声明 | @Path | @*Param |
Spring Web MVC | 服务端声明 | @RequestMapping | @RequestParam |
Spring Cloud Open Feign 利用 Feign 高扩展性,使用标准 Spring Web MVC 来声明客户端 Java 接口
- Feign
- 注解扩展性
- HTTP 请求处理
- REST 请求元信息解析
- Spring Cloud Open Feign
- 提供 Spring Web MVC 注解处理
- 提供 Feign 自动装配
Spring Cloud Open Feign 是通过 Java 接口的方式来声明 REST 服务提 供者的请求元信息,通过调用 Java 接口的方式来实现 HTTP/REST 通 讯。
实现细节猜想
- Java 接口(以及方法)与 REST 提供者元信息如何映射
- @FeignClient 注解所指定的应用(服务)名称可能用到了服务发 现,一个服务可以对应多个服务实例(HOST:PORT)
- @EnableFeignClients 注解是如何感知或加载标注
- @FeignClient 的配置类(Bean)
- Feign 请求和响应的内容是如何序列化和反序列化对应的 POJO 的
Feign 扩展支持 ( Contract 接口扩展)
- 内建 Feign 注解
- JAX-RS 1/2 注解
- JAXB
- OkHttp
- …
Contract 接口扩展:提供 Feign 接口方法与 REST 请求元信息契 约,解析出相关的方法元信息
基本步骤
service-client -> service-provider( Spring Boot + Web MVC + 服务注 册与发现)
-
增加依赖
org.springframework.cloud:spring-cloud-starteropenfeign
-
激活Feign客户端
@SpringBootApplication @EnableFeignClients public class Application { ... }
-
定义Feign的接口
@FeignClient("stores") // "stores" 应用(服务)名称 public interface StoreClient { @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json") Store update(@PathVariable("storeId") Long storeId, Store store); }
常见一些Spring Boot/Cloud中的坑
@Value(“server.port”)服务端口不一定靠谱,当server.port为0时
@LocalServerPort
也不靠谱,因为在注入阶段"local.server.port"也不一定存在
Spring Cloud + Netflix Ribbon 有一个 30 秒延迟
DynamicServerListLoadBalancer
非 Eureka 实现 - com.netflix.loadbalancer.PollingServerListUpdater
Eureka 实现 - com.netflix.niws.loadbalancer.EurekaNotificationServerListUp dater
Spring Cloud 服务调用
- 服务发现 - DiscoveryClient(Eureka、ZK、Consul、Nacos 等)
- 负载均衡 - Netflix Ribbon(唯一选择)
- Feign (唯一选择)
Spring Cloud Open Feign 实现细节
@EnableFeignClients
实现策略:Enable 模块驱动
具体实现:org.springframework.cloud.openfeign.FeignClientsRegistrar
主要工作:
- 注册默认配置
- 注册所有标注 @FeignClient 配置类
注册默认配置
源码位置:
org.springframework.cloud.openfeign.FeignClientsRegistrar#regist erDefaultConfiguration
注册所有标注 @FeignClient 配置类
源码位置:
org.springframework.cloud.openfeign.FeignClientsRegistrar#regist erFeignClients
通过 ClassPathScanningCandidateComponentProvider
扫描指定 的 basePackages 集合中的类是否标注 @FeignClient,如果有的 话,作为 AnnotatedBeanDefinition 返回,其中包含 @FeignClient 属性元数据,来自于 AnnotationMetadata,再重新 注册 FeignClientFactoryBean 的 BeanDefinition
@EnableFeignClient -> @Feignclient 元信息 -> 标注接口定义的 FeignClientFactoryBean -> 形成被标注接口的代理对象
Spring Cloud Open Feign 大致流程:
- Spring Web MVC 注解元信息解析
- Contract Feign 内建实现
- @RequestLine
- @Headers
- JAX-RS 1/2 注解
- @Path
- @PathParam
- @HeaderParam
- Spring Web MVC ( Spring Cloud Open Feign 扩展)
- Contract Feign 内建实现
- 通过 @FeignClient 所生成代理对象的方法调用实现 HTTP 调用
- 通过 SpringDecoder 实现 Response 与接口返回类型的反序列化
- 负载均衡
- Spring Cloud 替换了 Client 实现 - LoadBalancerFeignClient
- 重试重试
- Spring Cloud 在外部包装 Feign 接口
- 熔断 feign.hystrix.HystrixFeign
Spring Boot Actuator
JMX
Web Endpint
Enable 模块驱动
org.springframework.context.annotation.ImportBeanDefinitionRegistrar
- @EnableFeignClients
org.springframework.context.annotation.ImportSelector
- @EnableAsync
- @Configuration 类
- @EnableWebMvc
Bean 注入的实现(DI 过程)
- 普通 Bean
- 编码 BeanDefintion 生成的
- XML 配置的
- 注解标注的
- 直接注册的
- FactoryBean 生成的
FactoryBean 是如何当做一个 Bean 被注入?
- 返回 Bean 类型
- getObjectType()
- 返回 Bean 对象
- getObject()
BeanFactory 依赖查找
- 通过名称查找
- getBean(String)
- 通过类型查找
- getBean(Class)
- 直接查找 BeanDefinition#getBeanClassName() : String
- 间接查找 BeanFactory#getObjectType
- getBean(Class)
- 通过名称 + 类型查找
- getBean(String,Class)
- 通过注解查找
- getBeansWithAnnotation(Annotation)
Spring Cloud 整合
- 整合负载均衡:Netflix Ribbon
- 整合服务短路路:Netflix Hystrix
- 整合服务发现:Netflix Eureka
- 整合配置服务器器:Config Server
- 整合配置客户端:Config Client
Spring Cloud Netflix Hystrix
-
Netflix Hystrix
- Hystrix: Latency and Fault Tolerance for Distributed Systems
- https://github.com/Netflix/Hystrix
- Maven 依赖
- com.netflix.hystrix:hystrix-core
-
Netflix Hystrix
- 整合 Spring
- 激活:@EnableHystrix
- 编程模型
- 注解⽅方式:@HystrixCommand
- 编程⽅方式:HystrixComman
- 整合 Spring
问题:设置server.port=0(表示随机端口)
- Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder ‘local.server.port’ in value “${local.server.port}”
import org.springframework.core.env.Environment;
@Autowired
private Environment environment;
String getPort() {
return environment.getProperty("local.server.port");
}