SOFARPC 服务端处理请求的详细流程包含多个关键步骤,以下将基于你提供的代码片段,详细介绍服务端处理请求的完整过程:
1. 请求接收
当客户端发起请求时,服务端需要接收该请求。以 BoltServerProcessor
为例,它继承自 AsyncUserProcessor<SofaRequest>
,用于处理接收到的 SofaRequest
。
public class BoltServerProcessor extends AsyncUserProcessor<SofaRequest> {
@Override
public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, SofaRequest request) {
// RPC内置上下文
RpcInternalContext context = RpcInternalContext.getContext();
context.setProviderSide(true);
// 其他处理逻辑...
}
}
在 handleRequest
方法中,首先获取 RpcInternalContext
并标记为服务端侧,然后设置远程地址和异步上下文等信息。
2. 事件发布
服务端接收到请求后,会触发 ServerReceiveEvent
事件,用于通知其他组件请求已到达。
if (EventBus.isEnable(ServerReceiveEvent.class)) {
EventBus.post(new ServerReceiveEvent(request));
}
3. 服务查找
服务端需要根据请求中的服务名查找对应的 Invoker
。
Invoke: {
if (!boltServer.isStarted()) {
// 服务端已关闭
throwable = new SofaRpcException(RpcErrorType.SERVER_CLOSED, LogCodes.getLog(
LogCodes.WARN_PROVIDER_STOPPED, SystemInfo.getLocalHost() + ":" +
boltServer.serverConfig.getPort()));
response = MessageBuilder.buildSofaErrorResponse(throwable.getMessage());
break invoke;
}
if (bizCtx.isRequestTimeout()) {
// 加上丢弃超时的请求的逻辑
throwable = clientTimeoutWhenReceiveRequest(appName, serviceName, bizCtx.getRemoteAddress());
break invoke;
}
// 查找服务
Invoker invoker = boltServer.findInvoker(serviceName);
if (invoker == null) {
throwable = cannotFoundService(appName, serviceName);
response = MessageBuilder.buildSofaErrorResponse(throwable.getMessage());
break invoke;
}
// 其他处理逻辑...
}
如果服务端未启动、请求超时或未找到对应的 Invoker
,会抛出相应的异常并构建错误响应。
4. 方法查找
找到服务对应的 Invoker
后,需要根据请求中的方法名查找具体的方法。
String methodName = request.getMethodName();
Method serviceMethod = ReflectCache.getOverloadMethodCache(serviceName, methodName,
request.getMethodArgSigs());
if (serviceMethod == null) {
throwable = cannotFoundServiceMethod(appName, methodName, serviceName);
response = MessageBuilder.buildSofaErrorResponse(throwable.getMessage());
break invoke;
} else {
request.setMethod(serviceMethod);
}
如果未找到对应的方法,会抛出异常并构建错误响应。
5. 实际调用
找到服务和方法后,会调用 Invoker
的 invoke
方法进行实际的业务处理。
private SofaResponse doInvoke(String serviceName, Invoker invoker, SofaRequest request) throws SofaRpcException {
// 开始调用,先记下当前的ClassLoader
ClassLoader rpcCl = Thread.currentThread().getContextClassLoader();
try {
// 切换线程的ClassLoader到 服务 自己的ClassLoader
ClassLoader serviceCl = ReflectCache.getServiceClassLoader(serviceName);
Thread.currentThread().setContextClassLoader(serviceCl);
return invoker.invoke(request);
} finally {
Thread.currentThread().setContextClassLoader(rpcCl);
}
}
在调用过程中,会切换线程的 ClassLoader
到服务自己的 ClassLoader
,以确保正确加载服务相关的类。
6. 响应处理
实际调用完成后,会得到一个 SofaResponse
对象,服务端需要对该响应进行处理并返回给客户端。
if (response != null) {
RpcInvokeContext invokeContext = RpcInvokeContext.peekContext();
isAsyncChain = CommonUtils.isTrue(invokeContext != null ?
(Boolean) invokeContext.remove(RemotingConstants.INVOKE_CTX_IS_ASYNC_CHAIN) : null);
// 如果是服务端异步代理模式,特殊处理,因为该模式是在业务代码自主异步返回的
if (!isAsyncChain) {
// 其它正常请求
try {
asyncCtx.sendResponse(response);
} finally {
if (EventBus.isEnable(ServerSendEvent.class)) {
EventBus.post(new ServerSendEvent(request, response, throwable));
}
}
}
}
如果响应不为空,会通过 AsyncContext
将响应发送给客户端,并触发 ServerSendEvent
事件。
7. 清理工作
最后,需要进行一些清理工作,如移除上下文信息等。
finally {
RecordContextResolver.carryWithRequest(bizCtx.getInvokeContext().getRecordContext(), request);
processingCount.decrementAndGet();
if (!isAsyncChain) {
if (EventBus.isEnable(ServerEndHandleEvent.class)) {
EventBus.post(new ServerEndHandleEvent());
}
}
RpcInvokeContext.removeContext();
RpcInternalContext.removeAllContext();
}