前两讲过了SOFA RPC的服务发布和SPI,再次基础上我们在讲一下服务调用,也就是consumer端,我们首先看一段SOFA RPC的example上面的一段代码:
/**
* Quick Start client
*/
public class QuickStartClient {
private final static Logger LOGGER = LoggerFactory.getLogger(QuickStartClient.class);
public static void main(String[] args) {
ConsumerConfig<HelloService> consumerConfig = new ConsumerConfig<HelloService>()
.setInterfaceId(HelloService.class.getName()) // 指定接口
.setProtocol("bolt") // 指定协议
.setDirectUrl("bolt://127.0.0.1:12200") // 指定直连地址
.setConnectTimeout(10 * 1000);
HelloService helloService = consumerConfig.refer();
while (true) {
try {
LOGGER.info(helloService.sayHello("world"));
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 引用服务
*
* @return 服务代理类 t
*/
public T refer() {
if (consumerBootstrap == null) {
consumerBootstrap = Bootstraps.from(this);
}
return consumerBootstrap.refer();
}
这个发布我们就以DefaultConsumerBootstrap为例
public T refer() {
if (proxyIns != null) {
return proxyIns;
}
synchronized (this) {
if (proxyIns != null) {
return proxyIns;
}
String key = consumerConfig.buildKey();
String appName = consumerConfig.getAppName();
// 检查参数,这里是空调用
checkParameters();
// 提前检查接口类
if (LOGGER.isInfoEnabled(appName)) {
LOGGER.infoWithApp(appName, "Refer consumer config : {} with bean id {}", key, consumerConfig.getId());
}
// 注意同一interface,同一tags,同一protocol情况
AtomicInteger cnt = REFERRED_KEYS.get(key); // 计数器
if (cnt == null) { // 没有发布过
cnt = CommonUtils.putToConcurrentMap(REFERRED_KEYS, key, new AtomicInteger(0));
}
int c = cnt.incrementAndGet();
int maxProxyCount = consumerConfig.getRepeatedReferLimit();
if (maxProxyCount > 0) {
if (c > maxProxyCount) {
cnt.decrementAndGet();
// 超过最大数量,直接抛出异常
throw new SofaRpcRuntimeException("Duplicate consumer config with key " + key
+ " has been referred more than " + maxProxyCount + " times!"
+ " Maybe it's wrong config, please check it."
+ " Ignore this if you did that on purpose!");
} else if (c > 1) {
if (LOGGER.isInfoEnabled(appName)) {
LOGGER.infoWithApp(appName, "Duplicate consumer config with key {} has been referred!"
+ " Maybe it's wrong config, please check it."
+ " Ignore this if you did that on purpose!", key);
}
}
}
try {
// build cluster,根据SPI加载配置的路由
cluster = ClusterFactory.getCluster(this);
// build listeners,设置监听器,这个作用主要是用来做路由改变时自动更新providerGroup
consumerConfig.setConfigListener(buildConfigListener(this));
consumerConfig.setProviderInfoListener(buildProviderInfoListener(this));
// init cluster,这里加上前面的几步都是用来构建路由,并且设置变化监听
cluster.init();
// 构造Invoker对象(执行链)
proxyInvoker = buildClientProxyInvoker(this);
// 创建代理类
proxyIns = (T) ProxyFactory.buildProxy(consumerConfig.getProxy(), consumerConfig.getProxyClass(),
proxyInvoker);
//动态配置
final String dynamicAlias = consumerConfig.getParameter(DynamicConfigKeys.DYNAMIC_ALIAS);
if (StringUtils.isNotBlank(dynamicAlias)) {
final DynamicConfigManager dynamicManager = DynamicConfigManagerFactory.getDynamicManager(
consumerConfig.getAppName(), dynamicAlias);
dynamicManager.initServiceConfiguration(consumerConfig.getInterfaceId());
}
} catch (Exception e) {
if (cluster != null) {
cluster.destroy();
cluster = null;
}
consumerConfig.setConfigListener(null);
consumerConfig.setProviderInfoListener(null);
cnt.decrementAndGet(); // 发布失败不计数
if (e instanceof SofaRpcRuntimeException) {
throw (SofaRpcRuntimeException) e;
} else {
throw new SofaRpcRuntimeException("Build consumer proxy error!", e);
}
}
if (consumerConfig.getOnAvailable() != null && cluster != null) {
cluster.checkStateChange(false); // 状态变化通知监听器
}
RpcRuntimeContext.cacheConsumerConfig(this);
return proxyIns;
}
}
我们来看下这个服务调用都做了些啥:
1、构建自动路由寻址
2、构造Invoker对象执行链,创建代理类
3、加载一些动态配置
我们来看下第一步:
public synchronized void init() {
if (initialized) { // 已初始化
return;
}
// 构造Router链
routerChain = RouterChain.buildConsumerChain(consumerBootstrap);
// 负载均衡策略 考虑是否可动态替换?
loadBalancer = LoadBalancerFactory.getLoadBalancer(consumerBootstrap);
// 地址管理器
addressHolder = AddressHolderFactory.getAddressHolder(consumerBootstrap);
// 连接管理器
connectionHolder = ConnectionHolderFactory.getConnectionHolder(consumerBootstrap);
// 构造Filter链,最底层是调用过滤器
this.filterChain = FilterChain.buildConsumerChain(this.consumerConfig,
new ConsumerInvoker(consumerBootstrap));
if (consumerConfig.isLazy()) { // 延迟连接
if (LOGGER.isInfoEnabled(consumerConfig.getAppName())) {
LOGGER.infoWithApp(consumerConfig.getAppName(), "Connection will be initialized when first invoke.");
}
}
// 启动重连线程
connectionHolder.init();
try {
// 得到服务端列表
List<ProviderGroup> all = consumerBootstrap.subscribe();
if (CommonUtils.isNotEmpty(all)) {
// 初始化服务端连接(建立长连接)
updateAllProviders(all);
}
} catch (SofaRpcRuntimeException e) {
throw e;
} catch (Throwable e) {
throw new SofaRpcRuntimeException("Init provider's transport error!", e);
}
// 启动成功
initialized = true;
// 如果check=true表示强依赖
if (consumerConfig.isCheck() && !isAvailable()) {
throw new SofaRpcRuntimeException("The consumer is depend on alive provider " +
"and there is no alive provider, you can ignore it " +
"by ConsumerConfig.setCheck(boolean) (default is false)");
}
}
/**
* 构建Router链
*
* @param consumerBootstrap 服务端订阅者配置
* @return 路由链
*/
public static RouterChain buildConsumerChain(ConsumerBootstrap consumerBootstrap) {
// 获取到调用者配置
ConsumerConfig<?> consumerConfig = consumerBootstrap.getConsumerConfig();
// 初始化配置路由,如果没有配置就是空的
List<Router> customRouters = consumerConfig.getRouterRef() == null ? new ArrayList<Router>()
: new CopyOnWriteArrayList<Router>(consumerConfig.getRouterRef());
// 先解析是否有特殊处理,判断是否需要排除系统过滤器
HashSet<String> excludes = parseExcludeRouter(customRouters);
// 准备数据:用户通过别名的方式注入的router,需要解析
List<ExtensionClass<Router>> extensionRouters = new ArrayList<ExtensionClass<Router>>();
List<String> routerAliases = consumerConfig.getRouter();
if (CommonUtils.isNotEmpty(routerAliases)) {
for (String routerAlias : routerAliases) {
// 排除用的特殊字符,有"-"和"!"则会加入excludes
if (startsWithExcludePrefix(routerAlias)) {
excludes.add(routerAlias.substring(1));
} else {
// 使用spi加载获得ExtensionClass<Router>,EXTENSION_LOADER会自动初始化,因为是静态的
// 增加了监听,如果配置了AutoActive每次加载完毕会加入CONSUMER_AUTO_ACTIVES
extensionRouters.add(EXTENSION_LOADER.getExtensionClass(routerAlias));
}
}
}
// 解析自动加载的router
// 配了-*和-default表示不加载内置
if (!excludes.contains(StringUtils.ALL) && !excludes.contains(StringUtils.DEFAULT)) {
for (Map.Entry<String, ExtensionClass<Router>> entry : CONSUMER_AUTO_ACTIVES.entrySet()) {
if (!excludes.contains(entry.getKey())) {
extensionRouters.add(entry.getValue());
}
}
}
excludes = null; // 不需要了
// 按order从小到大排序
if (extensionRouters.size() > 1) {
Collections.sort(extensionRouters, new OrderedComparator<ExtensionClass>());
}
List<Router> actualRouters = new ArrayList<Router>();
for (ExtensionClass<Router> extensionRouter : extensionRouters) {
// 初始化
Router actualRoute = extensionRouter.getExtInstance();
actualRouters.add(actualRoute);
}
// 加入自定义的过滤器
actualRouters.addAll(customRouters);
return new RouterChain(actualRouters, consumerBootstrap);
}
构建路由链完毕,接下来的负载均衡策略,地址管理器,连接管理器都只是通过SPI加载一下没有做特殊处理,我们先过了,我们来看下构造Filter链
// 构造Filter链,最底层是调用过滤器
this.filterChain = FilterChain.buildConsumerChain(this.consumerConfig,
new ConsumerInvoker(consumerBootstrap));
/**
* 构造调用端的执行链
*
* @param consumerConfig consumer配置
* @param lastFilter 最后一个filter
* @return filter执行链
*/
public static FilterChain buildConsumerChain(ConsumerConfig<?> consumerConfig, FilterInvoker lastFilter) {
// selectActualFilters 这个方法和我们讲的上面的buildConsumerChain逻辑是一样的,这里不再赘述
return new FilterChain(selectActualFilters(consumerConfig, CONSUMER_AUTO_ACTIVES), lastFilter, consumerConfig);
}
/**
* 构造执行链
*
* @param filters 包装过滤器列表
* @param lastInvoker 最终过滤器
* @param config 接口配置
*/
protected FilterChain(List<Filter> filters, FilterInvoker lastInvoker, AbstractInterfaceConfig config) {
// 调用过程外面包装多层自定义filter
// 前面的过滤器在最外层
invokerChain = lastInvoker;
if (CommonUtils.isNotEmpty(filters)) {
loadedFilters = new ArrayList<Filter>();
for (int i = filters.size() - 1; i >= 0; i--) {
try {
Filter filter = filters.get(i);
// 是否需要加载。默认是可以加载的,如果重写了needToLoad就按自己实现的来
if (filter.needToLoad(invokerChain)) {
invokerChain = new FilterInvoker(filter, invokerChain, config);
// cache this for filter when async respond
loadedFilters.add(filter);
}
} catch (Exception e) {
LOGGER.error("Error when build filter chain", e);
throw new SofaRpcRuntimeException("Error when build filter chain", e);
}
}
}
}
接下来看下启动重连线程
// 启动重连线程
connectionHolder.init();
/**
* 启动重连+心跳线程
*/
protected void startReconnectThread() {
final String interfaceId = consumerConfig.getInterfaceId();
// 启动线程池
// 默认每隔10秒重连
int reconnect = consumerConfig.getReconnectPeriod();
if (reconnect > 0) {
reconnect = Math.max(reconnect, 2000); // 最小2000
reconThread = new ScheduledService("CLI-RC-" + interfaceId, ScheduledService.MODE_FIXEDDELAY, new
Runnable() {
@Override
public void run() {
try {
doReconnect();
} catch (Throwable e) {
LOGGER.errorWithApp(consumerConfig.getAppName(),
"Exception when retry connect to provider", e);
}
}
}, reconnect, reconnect, TimeUnit.MILLISECONDS).start();
}
}
/**
* 重连断开和死亡的节点
*/
private void doReconnect() {
String interfaceId = consumerConfig.getInterfaceId();
String appName = consumerConfig.getAppName();
int thisTime = reconnectFlag.incrementAndGet();
boolean print = thisTime % 6 == 0; //是否打印error,每6次打印一次
boolean isAliveEmptyFirst = isAvailableEmpty();
// 检查可用连接 todo subHealth
for (Map.Entry<ProviderInfo, ClientTransport> alive : aliveConnections.entrySet()) {
ClientTransport connection = alive.getValue();
if (connection != null && !connection.isAvailable()) {
aliveToRetry(alive.getKey(), connection);
}
}
for (Map.Entry<ProviderInfo, ClientTransport> entry : getRetryConnections()
.entrySet()) {
ProviderInfo providerInfo = entry.getKey();
int providerPeriodCoefficient = CommonUtils.parseNum((Integer)
providerInfo.getDynamicAttr(ProviderInfoAttrs.ATTR_RC_PERIOD_COEFFICIENT), 1);
if (thisTime % providerPeriodCoefficient != 0) {
continue; // 如果命中重连周期,则进行重连
}
ClientTransport transport = entry.getValue();
if (LOGGER.isDebugEnabled(appName)) {
LOGGER.debugWithApp(appName, "Retry connect to {} provider:{} ...", interfaceId, providerInfo);
}
try {
transport.connect();
// 双重检查,防止连上就被踢下线,如果重连成功
if (doubleCheck(interfaceId, providerInfo, transport)) {
providerInfo.setDynamicAttr(ProviderInfoAttrs.ATTR_RC_PERIOD_COEFFICIENT, 1);
// 从重试列表放入存活列表
retryToAlive(providerInfo, transport);
}
} catch (Exception e) {
if (print) {
if (LOGGER.isWarnEnabled(appName)) {
LOGGER.warnWithApp(appName, "Retry connect to {} provider:{} error ! The exception is " + e
.getMessage(), interfaceId, providerInfo);
}
} else {
if (LOGGER.isDebugEnabled(appName)) {
LOGGER.debugWithApp(appName, "Retry connect to {} provider:{} error ! The exception is " + e
.getMessage(), interfaceId, providerInfo);
}
}
}
}
if (isAliveEmptyFirst && !isAvailableEmpty()) { // 原来空,变成不空
// 通知监听器现在已经有可请求的服务了
notifyStateChangeToAvailable();
}
}