从jsonRpc接入http请求直至开始业务逻辑处理总体层级如下:
JsonServiceExporter->handleRequest-> handle -> handleRequest0 ->handleRequest -> handleJsonNodeRequest -> handleObject -> methodInvoke
package com.googlecode.jsonrpc4j.spring;
import com.googlecode.jsonrpc4j.JsonRpcServer;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;
class JsonServiceExporter extends AbstractJsonServiceExporter implements HttpRequestHandler {
private JsonRpcServer jsonRpcServer;
JsonServiceExporter() {
}
protected void exportService() {
this.jsonRpcServer = this.getJsonRpcServer();
}
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.jsonRpcServer.handle(request, response);
response.getOutputStream().flush();
}
}
/**
* Handles a servlet request.
*
* @param request the {@link HttpServletRequest}
* @param response the {@link HttpServletResponse}
* @throws IOException on error
*/
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
logger.debug("Handling HttpServletRequest {}", request);
response.setContentType(contentType);
OutputStream output = response.getOutputStream();
InputStream input = getRequestStream(request);
int result = ErrorResolver.JsonError.PARSE_ERROR.code;
int contentLength = 0;
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
try {
String acceptEncoding = request.getHeader(ACCEPT_ENCODING);
result = handleRequest0(input, output, acceptEncoding, response, byteOutput);
contentLength = byteOutput.size();
} catch (Throwable t) {
if (StreamEndedException.class.isInstance(t)) {
logger.debug("Bad request: empty contents!");
} else {
logger.error(t.getMessage(), t);
}
}
int httpStatusCode = httpStatusCodeProvider == null ? DefaultHttpStatusCodeProvider.INSTANCE.getHttpStatusCode(result)
: httpStatusCodeProvider.getHttpStatusCode(result);
response.setStatus(httpStatusCode);
response.setContentLength(contentLength);
byteOutput.writeTo(output);
output.flush();
}
/**
* Handles a single request from the given {@link InputStream},
* that is to say that a single {@link JsonNode} is read from
* the stream and treated as a JSON-RPC request. All responses
* are written to the given {@link OutputStream}.
*
* @param input the {@link InputStream}
* @param output the {@link OutputStream}
* @return the error code, or {@code 0} if none
* @throws IOException on error
*/
public int handleRequest(final InputStream input, final OutputStream output) throws IOException {
final ReadContext readContext = ReadContext.getReadContext(input, mapper);
try {
readContext.assertReadable();
final JsonNode jsonNode = readContext.nextValue();
for (JsonRpcInterceptor interceptor : interceptorList) {
interceptor.preHandleJson(jsonNode);
}
JsonResponse jsonResponse = handleJsonNodeRequest(jsonNode);
writeAndFlushValue(output, jsonResponse.getResponse());
if (jsonResponse.getExceptionToRethrow() != null) {
throw jsonResponse.getExceptionToRethrow();
}
return jsonResponse.getCode();
} catch (JsonParseException | JsonMappingException e) {
JsonResponse responseError = createResponseError(VERSION, NULL, JsonError.PARSE_ERROR);
writeAndFlushValue(output, responseError.getResponse());
return responseError.getCode();
}
}
/**
* Handles the given {@link JsonNode} and creates {@link JsonResponse}
*
* @param node the {@link JsonNode}
* @return the {@link JsonResponse} instance
*/
protected JsonResponse handleJsonNodeRequest(final JsonNode node)
throws JsonParseException, JsonMappingException {
if (node.isArray()) {
return handleArray((ArrayNode) node);
}
if (node.isObject()) {
return handleObject((ObjectNode) node);
}
return createResponseError(VERSION, NULL, JsonError.INVALID_REQUEST);
}
REQUEST);
}
/**
* Handles the given {@link ObjectNode} and creates {@link JsonResponse}
*
* @param node the {@link JsonNode}
* @return the {@link JsonResponse} instance
*/
private JsonResponse handleObject(final ObjectNode node)
throws JsonParseException, JsonMappingException {
logger.debug("Request: {}", node);
// 验证请求中是否存在"jsonRpc" 以及 "method"
if (!isValidRequest(node)) {
return createResponseError(VERSION, NULL, JsonError.INVALID_REQUEST);
}
// 获取对应请求id
Object id = parseId(node.get(ID));
// 验证参数是否为空
String jsonRpc = hasNonNullData(node, JSONRPC) ? node.get(JSONRPC).asText() : VERSION;
if (!hasNonNullData(node, METHOD)) {
return createResponseError(jsonRpc, id, JsonError.METHOD_NOT_FOUND);
}
// 获取方法路径信息
final String fullMethodName = node.get(METHOD).asText();
final String partialMethodName = getMethodName(fullMethodName);
final String serviceName = getServiceName(fullMethodName);
Set<Method> methods = findCandidateMethods(getHandlerInterfaces(serviceName), partialMethodName);
if (methods.isEmpty()) {
return createResponseError(jsonRpc, id, JsonError.METHOD_NOT_FOUND);
}
// 验证方法参数是否齐全
AMethodWithItsArgs methodArgs = findBestMethodByParamsNode(methods, node.get(PARAMS));
if (methodArgs == null) {
return createResponseError(jsonRpc, id, JsonError.METHOD_PARAMS_INVALID);
}
try (InvokeListenerHandler handler = new InvokeListenerHandler(methodArgs, invocationListener)) {
try {
// 若设置预处理拦截器则会在此处拦截请求
if (this.requestInterceptor != null) {
this.requestInterceptor.interceptRequest(node);
}
// serviceName 其实就是我们通过@JsonRpcService设置的层级,在程序启动时会自动加载到内存当中
Object target = getHandler(serviceName);
// interceptors preHandle
for (JsonRpcInterceptor interceptor : interceptorList) {
interceptor.preHandle(target, methodArgs.method, methodArgs.arguments);
}
// invocation 做内部方法调用执行业务逻辑
JsonNode result = invoke(target, methodArgs.method, methodArgs.arguments);
handler.result = result;
// interceptors postHandle 若设置post拦截器则会在此处拦截请求
for (JsonRpcInterceptor interceptor : interceptorList) {
interceptor.postHandle(target, methodArgs.method, methodArgs.arguments, result);
}
// 验证id不为空
if (!isNotificationRequest(id)) {
return createResponseSuccess(jsonRpc, id, handler.result);
}
return new JsonResponse(null, JsonError.OK.code);
} catch (JsonParseException | JsonMappingException e) {
throw e; // rethrow this, it will be handled as PARSE_ERROR later
} catch (Throwable e) {
handler.error = e;
return handleError(id, jsonRpc, methodArgs, e);
}
}
}