SpringMVC原始碼解析(四)之關於json,xml的自動轉換原理
關於json,xml的自動轉換原理的核心就在messageConvert,前一篇我們已經分析到通過messageConvert對請求引數進行解析讀取,那就續點分析。
本節就以json的轉換為例(xml類同只是不同的messageConvert)來進行分析,在我們對請求引數解析時候回顧下readWithMessageConverters方法
body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
通過converter讀取請求訊息
那麼問題來了,這些messageConverts哪來的呢?
我們知道RequestMappingHandlerAdapter是請求處理的介面卡,也就是請求之後處理具體邏輯的執行,關係到哪個類的哪個方法以及轉換器等工作,這個類是我們講的重點,其中它的屬性messageConverters就是我們關注的重點
RequestMappingHandlerAdapter有個預設建構函式
public RequestMappingHandlerAdapter() { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter很明顯在建立物件例項的時候 就對messageConverters進行了賦值,最後新增的AllEncompassingFormHttpMessageConverter 所有包含的FormHttpMessageConverter,看看究竟有哪些(); stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316 this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4); this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(stringHttpMessageConverter); this.messageConverters.add(new SourceHttpMessageConverter<Source>()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); }
if條件的值 則是
private static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", AllEncompassingFormHttpMessageConverter.class.getClassLoader()); private static final boolean jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", AllEncompassingFormHttpMessageConverter.class.getClassLoader()); private static final boolean jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader()); private static final boolean gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
也就是當com.fasterxml.jackson.databind.ObjectMapper和com.fasterxml.jackson.core.JsonGenerator存在在classpath中才會去載入MappingJackson2HttpMessageConverter。(其他一樣的道理)
現在是不是知道了 為什麼 springMVC預設就支援json轉換器,不過這裡我用fastjson作為分析例子
messageConverter的read方法
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException { return readInternal(clazz, inputMessage); }FastJsonHttpMessageConverter的readInternal方法為:
protected Object readInternal(Class<? extends Object> clazz, // HttpInputMessage inputMessage // ) throws IOException, HttpMessageNotReadableException { InputStream in = inputMessage.getBody(); return JSON.parseObject(in, fastJsonConfig.getCharset(), clazz, fastJsonConfig.getFeatures()); }可以看到就是把請求訊息體輸入流轉換為json物件,這就是整個訊息轉化為json的過程
下面我們解析分析 是如何將@ResponseBody註解標準的Controller方法返回的java物件轉換為json的
還記得之前RequestMappingHandlerAdapter中invokeAndHandle方法麼,其中也包含了對返回值的處理
this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
handleReturnValule方法的具體實現:
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }首先通過返回值以及返回型別搜尋對應的returnValueHandler,其次再通過得到的handler對返回訊息進行處理
handleRreturnValue的實現為
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, webRequest); }沒有似曾相識的感覺 之前我們分析解析請求訊息時候 有個readWithMessageConverters 現在又有個writeWithMessageConverters方法,那我們看看具體實現:
方法中程式碼太多,中間一段略過。。。。。
write方法是程式碼如下:
public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { final HttpHeaders headers = outputMessage.getHeaders(); addDefaultHeaders(headers, t, contentType); if (outputMessage instanceof StreamingHttpOutputMessage) { StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage; streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() { @Override public void writeTo(final OutputStream outputStream) throws IOException { writeInternal(t, new HttpOutputMessage() { @Override public OutputStream getBody() throws IOException { return outputStream; } @Override public HttpHeaders getHeaders() { return headers; } }); } }); } else { writeInternal(t, outputMessage); outputMessage.getBody().flush(); } }我們重點關注writeInternal方法的實現,在FastJsonHttpMessageConverter中為
protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { HttpHeaders headers = outputMessage.getHeaders(); ByteArrayOutputStream outnew = new ByteArrayOutputStream(); boolean writeAsToString = false; if (obj != null) { String className = obj.getClass().getName(); if ("com.fasterxml.jackson.databind.node.ObjectNode".equals(className)) { writeAsToString = true; } } if (writeAsToString) { String text = obj.toString(); OutputStream out = outputMessage.getBody(); out.write(text.getBytes()); if (fastJsonConfig.isWriteContentLength()) { headers.setContentLength(text.length()); } } else { int len = JSON.writeJSONString(outnew, // fastJsonConfig.getCharset(), // obj, // fastJsonConfig.getSerializeConfig(), // fastJsonConfig.getSerializeFilters(), // fastJsonConfig.getDateFormat(), // JSON.DEFAULT_GENERATE_FEATURE, // fastJsonConfig.getSerializerFeatures()); if (fastJsonConfig.isWriteContentLength()) { headers.setContentLength(len); } OutputStream out = outputMessage.getBody(); outnew.writeTo(out); } outnew.close(); }
此方法中將Java物件轉換為json字串
其他訊息轉換器類似,如果讀者感興趣可自己去檢視程式碼研究,這裡就不作分析拉