- gPRC 介绍
- gPRC 介绍 - 资料收集整理
- gPRC 介绍 - Protocol Buffer 3
- gPRC文档
- gPRC文档 - gRPC官方文档(中文版)
- gPRC文档 - gRPC动机和设计原则
- gPRC文档 - 源码导航
- 基础 - NameResolver
- NameResolver - URI术语
- NameResolver - 类NameResolver
- NameResolver - 类DnsNameResolver
- NameResolver - 类DirectAddressNameResolver
- NameResolver - NameResolver的用法
- 基础 - Metadata
- Channel层
- Channel设计与代码实现 - 类Channel
- Channel设计与代码实现 - 类ManagedChannel
- 类ManagedChannelImpl - 空闲模式
- 类ManagedChannelImpl - InUseStateAggregator
- 类ManagedChannelImpl - Name Resolver
- 类ManagedChannelImpl - Load Balancer
- 类ManagedChannelImpl - Transport
- 类ManagedChannelImpl - Executor
- 类ManagedChannelImpl - 关闭
- Channel层 - Channel Builder设计与代码实现
- Channel Builder设计与代码实现 - 类ManagedChannelBuilder
- Channel Builder设计与代码实现 - 类AbstractManagedChannelImplBuilder
- Channel Builder设计与代码实现 - 类NettyChannelBuilder
- Channel层 - Channel Provider设计与代码实现
- Channel Provider设计与代码实现 - 类ManagedChannelProvider
- Channel Provider设计与代码实现 - 类NettyChannelProvider
- Channel层 - 类CallOptions
- Stub层 - 类DemoServiceBlockingStub
- Stub层 - 类AbstractStub
- 客户端流程
- 状态 - 类Status
- 状态 - 状态码详细定义
- 状态 - 类StatusException
- 状态 - 异常处理的流程分析
- 实践 - 集成Spring Boot
- 实践 - 文档生成
- 文档生成 - 支持proto3
- 文档生成 - build插件
- 文档生成 - 使用模板定制输出
- 实践 - 代理
- 实践 - 超时
Channel Provider设计与代码实现 - 类ManagedChannelProvider
ManagedChannelProvider 是 managed channel 的提供者,用于 transport 的不可知消费。
ManagedChannelProvider 的实现类不能抛出(异常)。如果抛出了,可能打断类装载。如果因为实现特有的原因会发生异常,实现应该优雅的处理异常并从 isAvailable() 方法返回 false 。
注:以上说明,来自 ManagedChannelProvider 的 Javadoc。
类定义
package io.grpc;
@Internal
public abstract class ManagedChannelProvider {}
静态初始化
上面Javadoc的描述中提到的”类不能抛出异常,否则会打断类装载”,说的应该就是这个静态初始化的操作:
private static final ManagedChannelProvider provider
= load(getCorrectClassLoader());
getCorrectClassLoader()方法先获取正确的ClassLoader:
private static ClassLoader getCorrectClassLoader() {
if (isAndroid()) {
//对于android平台,特殊一些
return ManagedChannelProvider.class.getClassLoader();
}
//其他情况,默认都是取当前线程的Context ClassLoader
return Thread.currentThread().getContextClassLoader();
}
然后load()方法装载并选择ManagedChannelProvider的具体实现,这里有三个步骤:
- 装载所有可能的候选者
- 排除掉不可用的候选者
- 选择优先级最高的候选者
load()方法的具体代码:
static ManagedChannelProvider load(ClassLoader classLoader) {
Iterable<ManagedChannelProvider> candidates;
if (isAndroid()) {
// 对于android平台,直接hard code候选者
candidates = getCandidatesViaHardCoded(classLoader);
} else {
// 其他情况,通过JDK的ServiceLoader装载候选者
candidates = getCandidatesViaServiceLoader(classLoader);
}
List<ManagedChannelProvider> list = new ArrayList<ManagedChannelProvider>();
for (ManagedChannelProvider current : candidates) {
// 排除掉不可用的候选者
if (!current.isAvailable()) {
continue;
}
list.add(current);
}
if (list.isEmpty()) {
// 如果为空返回null
return null;
} else {
// 返回优先级最高的候选者
return Collections.max(list, new Comparator<ManagedChannelProvider>() {
@Override
public int compare(ManagedChannelProvider f1, ManagedChannelProvider f2) {
return f1.priority() - f2.priority();
}
});
}
}
逻辑很清晰,继续看其中的两个细节,看候选者是如何被装载出来的。
android平台:hard code 两个可能的实现 okhttp 和 netty,如果类装载就只能忽略
public static Iterable<ManagedChannelProvider> getCandidatesViaHardCoded(
ClassLoader classLoader) {
List<ManagedChannelProvider> list = new ArrayList<ManagedChannelProvider>();
try {
list.add(create(Class.forName("io.grpc.okhttp.OkHttpChannelProvider", true, classLoader)));
} catch (ClassNotFoundException ex) {
// ignore
}
try {
list.add(create(Class.forName("io.grpc.netty.NettyChannelProvider", true, classLoader)));
} catch (ClassNotFoundException ex) {
// ignore
}
return list;
}
普通平台:标准的JDK ServiceLoader 方式
public static Iterable<ManagedChannelProvider> getCandidatesViaServiceLoader(
ClassLoader classLoader) {
return ServiceLoader.load(ManagedChannelProvider.class, classLoader);
}
最重要的provider()方法
对于调用者来说,最重要的就是 provider()方法,因为通常调用者都是这样使用:
ManagedChannelProvider provider = ManagedChannelProvider.provider();
......
provider()方法的实现很简单,判断一下静态变量 provider ,如果为空则抛出异常 ProviderNotFoundException,提示没有可用的 channel service provider:
public static ManagedChannelProvider provider() {
if (provider == null) {
throw new ProviderNotFoundException("No functional channel service provider found. " + "Try adding a dependency on the grpc-okhttp or grpc-netty artifact");
}
return provider;
}
和装载相关的抽象方法
在load()方法中,每个装载到的候选者,都需要实现这两个方法以便调用。
isAvailable()
用来判断这个provider是否可用,需要考虑当前环境。如果返回 false,则其他任何方法都不安全。
protected abstract boolean isAvailable();
实际在 load() 方法中,所有isAvailable()返回false的候选者都被直接排除。
priority()
优先级,每个provider可用的范围是从1到10,需要考虑当前环境。5被视为默认值,然后根据环境检测调整。优先级0 并不是暗示这个provider不工作,只是会排在最后。
protected abstract int priority();
创建ChannelBuilder的抽象方法
ManagedChannelProvider 的主要功能,还是在于创建适当的 ManagedChannelBuilder,在 ManagedChannelBuilder 中定义了两个抽象方法要求子类做具体实现:
builderForAddress(): 使用给定的host和端口创建新的builder
protected abstract ManagedChannelBuilder< ?> builderForAddress(String name, int port);
builderForTarget(): 使用给定的target URI来创建新的builder
protected abstract ManagedChannelBuilder< ?> builderForTarget(String target);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论