类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);