Spring 支持 Restful风格 源码分析

来源:互联网 发布:北京淘宝美工培训2ds 编辑:程序博客网 时间:2024/06/03 12:49

Spring 支持 Restful风格 源码分析

Restful风格API接口开发springMVC -- jsonRestful 请求处理 和 响应RequestResponseBodyMethodProcessor     return parameter.hasParameterAnnotation(RequestBody.class); //解析方法-属性带有@RequestBody的参数for (HttpMessageConverter<?> converter : this.messageConverters) { } //遍历所有的消息转换器,包括我们自定义的this.messageConverters // 在什么时候初始化的??AnnotationMethodHandlerAdapter -- RequestMappingHandlerAdapter //配置文件 -- 实际操作的RequestMappingHandlerAdapter.afterPropertiesSet() //由于RequestMappingHandlerAdapter实现InitializingBean接口,所以容器初始化时(启动的时候) 就会去执行这个方法,完成一些初始化的工作RequestMappingHandlerAdapter.getDefaultArgumentResolvers() //完成如下一些参数解析器类的初始化resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));resolvers.add(new RequestParamMapMethodArgumentResolver());resolvers.add(new PathVariableMethodArgumentResolver());resolvers.add(new PathVariableMapMethodArgumentResolver());resolvers.add(new MatrixVariableMethodArgumentResolver());resolvers.add(new MatrixVariableMapMethodArgumentResolver());resolvers.add(new ServletModelAttributeMethodProcessor(false));resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));resolvers.add(new RequestHeaderMapMethodArgumentResolver());resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));// Type-based argument resolutionresolvers.add(new ServletRequestMethodArgumentResolver());resolvers.add(new ServletResponseMethodArgumentResolver());resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));resolvers.add(new RedirectAttributesMethodArgumentResolver());resolvers.add(new ModelMethodProcessor());resolvers.add(new MapMethodProcessor());resolvers.add(new ErrorsMethodArgumentResolver());resolvers.add(new SessionStatusMethodArgumentResolver());resolvers.add(new UriComponentsBuilderMethodArgumentResolver());RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter //同时该类还继承 private List<HttpMessageConverter<?>> messageConverters; //且有成员变量消息转换器的list集合//并完成默认构造器来注册默认的消息转换器public RequestMappingHandlerAdapter() {    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();    stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316    this.messageConverters = new ArrayList<HttpMessageConverter<?>>();    this.messageConverters.add(new ByteArrayHttpMessageConverter());    this.messageConverters.add(stringHttpMessageConverter);    this.messageConverters.add(new SourceHttpMessageConverter<Source>());    this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());}//而对应自定义的AnnotationMethodHandlerAdapter 依赖的MappingJacksonHttpMessageConverter,通过xml文件的解析可以将消息转换器注册到RequestMappingHandlerAdapter//判断给定的类是否可以由这个转换器读取。if (converter.canRead(targetClass, contentType)) {     //使用这个消息转换器去转换    return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);}StringHttpMessageConverter //String请求的消息转换器//去解析处理clazz:是一个String的类型,inputMessage:是一个请求输入流的类型StringHttpMessageConverter{return readInternal(clazz, inputMessage);} //把HttpRequest请求参数解析成一个StringBuilder,并返回return StreamUtils.copyToString(inputMessage.getBody(), charset);//回去socket请求的输入流,解析输入流于StringBuilder,并返回给调用者public static String copyToString(InputStream in, Charset charset) throws IOException {    Assert.notNull(in, "No InputStream specified");    StringBuilder out = new StringBuilder();    InputStreamReader reader = new InputStreamReader(in, charset);    char[] buffer = new char[BUFFER_SIZE];    int bytesRead = -1;    while ((bytesRead = reader.read(buffer)) != -1) {        out.append(buffer, 0, bytesRead);    }    return out.toString();}//前台请求虽然有多个消息转换器,但实际就只有一个去处理请求,StringHttpMessageConverter,所以我们经常说前后台交互就是String类型//当StringHttpMessageConverter处理完了就直接返回处理结果了,就不会再执行别的消息转换器了//所以在controller配置入参转换器是没有意义的,如:@ResponeBody String param,是体现不了json转换器的//拿到通过请求参数数组args来调用具体Method的invok(),调用成功后返回调用结果,returnValue为值ServletInvocableHandlerMethod.invokeAndHandle(){ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);}//如:public Map | String | List xxx 代表了请求后响应也对应了有多种情况,对应各种类型//处理返回值,也对应了返回值类型的装换HandlerMethodReturnValueHandlerComposite.handleReturnValue()//还是对应了Handler来处理返回值,还是采用相同的策略模式来处理HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);//这是RequestMappingHandlerAdapter在初始化的时候所注册的一些实例,就包括了方法参数解析器和方法返回参数解析器相关类的初始化public void afterPropertiesSet() {    if (this.argumentResolvers == null) {        List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();        this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);    }    if (this.initBinderArgumentResolvers == null) {        List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();        this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);    }    if (this.returnValueHandlers == null) {        List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);    }    initControllerAdviceCache();}//当返回值是String类型的,对应的HandlerMethodReturnValueHandler就会去处理对应返回类型//将返回值包装到ModelAndViewContainer容器中ViewNameMethodReturnValueHandler.handleReturnValue(){ //其中ModelAndViewContainer mavContainer    else if (returnValue instanceof String) {        String viewName = (String) returnValue;        mavContainer.setViewName(viewName); //返回的值就是一个视图的名称,就是一个具体的页面,        if (isRedirectViewName(viewName)) {            mavContainer.setRedirectModelScenario(true);        }}//这个方法是支持@ResponeBody Map | String | List 以json类型返回的调用方法RequestResponseBodyMethodProcessor.handleReturnValue(){    public void handleReturnValue(Object returnValue, MethodParameter returnType,            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)            throws IOException, HttpMediaTypeNotAcceptableException {        mavContainer.setRequestHandled(true); //*****很重要        if (returnValue != null) {            writeWithMessageConverters(returnValue, returnType, webRequest);        }    }}//遍历消息转换器for (HttpMessageConverter<?> messageConverter : messageConverters) { //和入参使用的消息转换器是一致的    //判断是否写     if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {         //使用消息转换器回写给调用者        ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);        return;    }}//创建ServletServerHttpRequest和ServletServerHttpResponseAbstractMessageConverterMethodProcessor.writeWithMessageConverters(T returnValue, //调用方法返回的值,如string | "5555" map | "name:55"                                                MethodParameter returnType, //HandlerMethodReturnValueHandler                                        NativeWebRequest webRequest)    throws IOException, HttpMediaTypeNotAcceptableException {ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}//object:是调用方法后的返回值 outputMessage:HttpOutputMessage 响应值MappingJacksonHttpMessageConverter.writeInternal(Object object, HttpOutputMessage outputMessage)//调用jackson api this.objectMapper.writeValue(jsonGenerator, object);//调用jackson api后将调用后的数据刷入outputMessage实体中(相当于给调用者的返回)writeInternal(t, outputMessage);outputMessage.getBody().flush();//重要,负者参数的解析和参数的返回RequestMappingHandlerAdapter.invokeAndHandle(){    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);//参数解析***    setResponseStatus(webRequest);    if (returnValue == null) {        if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {            mavContainer.setRequestHandled(true);            return;        }    }    else if (StringUtils.hasText(this.responseReason)) {        mavContainer.setRequestHandled(true); //请求类别***        return;    }    mavContainer.setRequestHandled(false);    try {        //参数返回***        this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);    }}//很重要** 相当于包装成ModelAndView返回给调用者return RequestMappingHandlerAdapter.getModelAndView(mavContainer, modelFactory, webRequest);//获取视图和实体信息private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,        ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {    modelFactory.updateModel(webRequest, mavContainer);    if (mavContainer.isRequestHandled()) { //当为@ResponeBody的时候为true,就直接返回给了数据,没有返回对应的页面        return null;    }    ModelMap model = mavContainer.getModel();    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); // 构造视图响应    if (!mavContainer.isViewReference()) {        mav.setView((View) mavContainer.getView());    }    if (model instanceof RedirectAttributes) {        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);        RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);    }    return mav;}//在此之前已经完成了ModelAndView实体的构建,接下来要完成视图的解析和渲染DispatcherServlet.processDispatchResult() //进程调度的结果{    render(mv, request, response); //渲染}// 解析视图view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);// 遍历所有的视图解析器去解析视图,如internalResolverViewfor (ViewResolver viewResolver : this.viewResolvers) {    View view = viewResolver.resolveViewName(viewName, locale); //viewName : 就是对应的返回页面    if (view != null) {        return view;    }}InternalResourceView.renderMergedOutputModel(){    // 确定请求调度程序的路径。如:WEB-INFO/index.jsp    String dispatcherPath = prepareForRendering(requestToExpose, response);    //为目标资源获取一个RequestDispatcher(通常是一个JSP)。    RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);}RequestDispatcher //就相当于一个servletrd.forward(requestToExpose, response); //可以做相应的转发工作,转发到一个页面mappedHandler.triggerAfterCompletion(request, response, null); //接着调用后置过滤器MappingJacksonHttpMessageConverter 的定义的作用,如果在配置文件中没有定义消息转换器,并且spring也没给你做消息转换这样在controller中使用@ResponeBody 是不支持Restful - json 风格的响应的//在实际返回值的时候是交给具体的自定义messageConverters消息转换器来转换的,不注册这个消息装换器是无法正常解析给调用者返回值的jsonfor (HttpMessageConverter<?> messageConverter : messageConverters) {    if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {        ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);        if (logger.isDebugEnabled()) {            logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +                    messageConverter + "]");        }        return;    }}//不加这个MappingJacksonHttpMessageConverter 是无法直接支持restful - json格式的//处理给前端返回map,list,string 还可以直接返回一个实体,这个实体可以用@ResponeBody+配置json装换器,来让它支持restful的响应
阅读全文
0 0
原创粉丝点击