可以现金的棋牌游戏 当前位置:首页>可以现金的棋牌游戏>正文

可以现金的棋牌游戏

发布时间:2018-11-13

原标题:SpringMVC源码情操陶冶-RequestMappingHandlerAdapter适配器

此时花雨还在下面忙碌,叶扬独自来到了大厦的楼顶,这里距离地面有着接近两百米,他站在大厦顶上,俯览着整个纽约市,这要比在屋内看更有情调。

大菠萝扑克美国人玩吗

“原来是这样啊?韩长官果然高明,佩服!”没想到“狮子”这样的硬汉也会奉承,这点韩非确实很意外,没想到的。
“竟有此事?看来我父王的那些侍卫中还隐藏着不少奸细,回头我得好好查一下。”敖常面无表情,“但我当时并不在现场,更不知道是谁暗算了我父王……”

波田鬼子急忙命令手下鬼子驱逐舰:“朝前面行进一段距离,封锁住江面,截断冲上来的中国兵的退路!”波田鬼子这招挺狠的,他知道在双方的炮艇纠缠在一起的时候是不能开炮的,这样杀伤自己人的概率比杀伤敌人的要大不少,与其这样,倒不如让那些驱逐舰朝前面行进一段距离,你中国兵的炮艇总得退回去吧,那我就在你的退路上等着你!

承接前文SpringMVC源码情操陶冶-HandlerAdapter适配器简析。RequestMappingHandlerAdapter适配器组件是专门处理RequestMappingHandlerMapping返回的HandlerMethod对象,由此对象返回相应的视图对象或者直接返回数据给客户端

RequestMappingHandlerAdapter的xml配置应用

常用的针对handlerAdapter适配器的配置如下

<mvc:annotation-driven>
    <!--对直接返回数据前端而不是视图的消息处理器配置-->
    <mvc:message-converters>
        <ref bean="jsonMessageConverter" />
        <ref bean="xmlMessageConverter" />
        <bean class="com.jing.springmvc.message.converter.StringHttpMessageConverter"/>
    </mvc:message-converters>
    <!--方法参数解析器-->
    <mvc:argument-resolvers>
        ....
    </mvc:argument-resolvers>
    <!--返回内容处理器,其会包含上述的mvc:message-converters配置-->
    <mvc:return-value-handlers>
        ...
    </mvc:return-value-handlers>
</mvc:annotation-driven>

RequestMappingHandlerAdapter代码层面解析

首先我们可以看下RequestMappingHandlerAdapter的构造函数

    /**
     * Default constructor.
     */
    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());
    }

上述代表如果不指定mvc:message-converters配置,则默认采用上述的消息处理器集合,反之则会采用配置的消息处理器而忽略默认的配置

再而我们继续看下RequestMappingHandlerAdapter.class的继承关系

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean{}

我们会看到非常熟悉的InitializingBean接口,其afterPropertiesSet()方法会在其内部属性设置完毕后被调用,首先我们就从这个方法入手。

RequestMappingHandlerAdapter#afterPropertiesSet()

代码如下

    @Override
    public void afterPropertiesSet() {
        // 加载mvc:argument-resolvers的配置信息以及应用默认的配置
        if (this.argumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        // 加载mvc:argument-resolvers的配置信息以及应用默认的配置
        if (this.initBinderArgumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        // 加载mvc:message-converters的配置信息以及应用默认的配置
        if (this.returnValueHandlers == null) {
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
        // 初始化缓存所有@ControllerAdvice类上的含有@ModelAttributes和@InitBinder注解方法集合
        initControllerAdviceCache();
    }

针对上述的代码我们罗列下默认的参数处理、返回值处理是配置哪些处理类

  1. 参数处理类列表

    private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
    
        // Annotation-based argument resolution
        // @RequestParam和@RequestParamMap
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
        // @PathVariable和@PathVariableMap
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        // @MatrixVariable和@MatrixVariableMap
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
        // @RequestBody
        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 resolution
        resolvers.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());
    
        // 加载mvc:argument-resolver的自定义配置
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }
    
        // Catch-all
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
        resolvers.add(new ServletModelAttributeMethodProcessor(true));
    
        return resolvers;
    }
    1. 主要应用于我们常用的方法参数的注解,比如@RequestParam@PathVarible@RequestBody等注解方法,多余的读者可自行分析

    2. 上述的@RequestBody@RequestPart注解处理类也会用到mvc:message-converter的配置

    3. 此处作下备注:RequestParamMethodArgumentResolver其也会处理不带注解的参数,默认根据代码的参数名去request对象拿取值

  2. 返回值处理类列表

    /**
     * Return the list of return value handlers to use including built-in and
     * custom handlers provided via {@link #setReturnValueHandlers}.
     */
    private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
    
        // Single-purpose return value types
        handlers.add(new ModelAndViewMethodReturnValueHandler());
        handlers.add(new ModelMethodProcessor());
        handlers.add(new ViewMethodReturnValueHandler());
        handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
        handlers.add(new HttpHeadersReturnValueHandler());
        handlers.add(new CallableMethodReturnValueHandler());
        handlers.add(new DeferredResultMethodReturnValueHandler());
        handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
    
        // Annotation-based return value types
        handlers.add(new ModelAttributeMethodProcessor(false));
        handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
    
        // Multi-purpose return value types
        handlers.add(new ViewNameMethodReturnValueHandler());
        handlers.add(new MapMethodProcessor());
    
        // 自定义的返回类型处理器
        if (getCustomReturnValueHandlers() != null) {
            handlers.addAll(getCustomReturnValueHandlers());
        }
    
        // Catch-all
        if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
            handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
        }
        else {
            handlers.add(new ModelAttributeMethodProcessor(true));
        }
    
        return handlers;
    }
    1. 主要应用于我们常用的方法返回类型,比如ModelModelAndViewViewString@ResponseBody等返回类型,多余的读者可自行分析

    2. 上述的@ResponseBody注解也会用到mvc:message-converter的配置,多用于将数据直接写入响应体中

RequestMappingHandlerAdapter#handleInternal()

完整的处理RequestMappingHandlerMapping所含有的对象HandlerMethod,废话少说,我们直接看下源码

@Override
    protected final ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        // checkAndPrepare,处理前的准备工作①
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            // 相应的类上存在@SessionAttribute注解则走此处
            // Always prevent caching in case of session attribute management.
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
        }
        else {
            // Uses configured default cacheSeconds setting.
            checkAndPrepare(request, response, true);
        }

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandleMethod(request, response, handlerMethod);
                }
            }
        }
        // invokeHandleMethod,处理HandleMethod对象开始业务逻辑②
        return invokeHandleMethod(request, response, handlerMethod);
    }

上述罗列了最主要的两个执行方法,按照先后顺序已标注为①和②,现在我们分别看下方法的逻辑

WebContentGenerator#checkAndPrepare()-检查并作预备工作①

我们直接通过源码来讲解

protected final void checkAndPrepare(
            HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified)
            throws ServletException {

        // 检查请求的方法是否被支持
        // RequestMappingHandlerAdapter默认指定的supportedMethods为null
        String method = request.getMethod();
        if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
            throw new HttpRequestMethodNotSupportedException(
                    method, StringUtils.toStringArray(this.supportedMethods));
        }

        // 检查是否session对象必须存在,默认为false
        if (this.requireSession) {
            if (request.getSession(false) == null) {
                throw new HttpSessionRequiredException("Pre-existing session required but none found");
            }
        }

        // 是否增加cache头响应,默认不加
        applyCacheSeconds(response, cacheSeconds, lastModified);
    }
  1. 从上述的代码解析看,此处只是为了检查请求的方式是否被支持、session对象是否必须存在、cache响应头是否需要新增。

  2. 通过代码跟踪与发现,RequestMappingHandlerAdapter对象并不需要上述的检查,所以此方法可略过

RequestMappingHandlerAdapter#invokeHandleMethod()-关键处理逻辑②

    /**
     * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
     * if view resolution is required.
     */
    private ModelAndView invokeHandleMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        // HandlerMethod对应实体类的@InitBinder注解方法集合以及所关联的@ControllAdvice注解类的@InitBinder方法集合
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 同上,对应@ModelAttribute方法集合
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        
        // 包装成ServletInvocableHandlerMethod对象
        ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
        
        // 整合model对象集合1.request对象的org.springframework.web.servlet.DispatcherServlet.INPUT_FLASH_MAP属性值 2.解析带@ModelAttribute注解的方法返回值 3.session保存的属性集合
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        
        // 异步请求的处理配置,servlet 3.0+才会被引用
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

        if (asyncManager.hasConcurrentResult()) {
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();

            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
        }
        
        // 处理业务逻辑
        requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        
        // 返回视图对象
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }

具体的代码备注上述已展示,可以看下最主要的部分ServletInvocableHandlerMethod#invokeAndHandle(),其实如何处理具体的业务逻辑

ServletInvocableHandlerMethod#invokeAndHandle()

直接上源码

public final void invokeAndHandle(ServletWebRequest webRequest,
            ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        // 处理业务逻辑代码得到返回值
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        
        // 设置返回状态码和返回信息,通常与@ResponseStatus结合使用
        setResponseStatus(webRequest);

        ....
        ....
        

        try {
            // 检索returnValueHandlers集合,查找对应返回类型的处理器用于处理请求
            this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }
  1. 上述代码如果方法结合了@ResponseStatus注解,则如果指定了reason字段值且非空,则会直接发送错误至前台,错误信息则为reason指定的内容。具体的可查看下@ResponseStatus注解文档

  2. 通过之前设置的returnValueHandlers集合来匹配返回类型从而处理多方式的响应

为了方便理解上述的第二点,举个处理@RequestBody@ResponseBody注解方法的返回方式,此处为RequestResponseBodyMethodProcessor

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException {
        // 设置处理状态为已处理
        mavContainer.setRequestHandled(true);
        // 一般此处的返回值为String对象或者自定义的对象,切记是一个对象,而非void
        if (returnValue != null) {
            // 此处就是通过mvc:message-converters指定的或者默认的消息处理器来处理内容
            writeWithMessageConverters(returnValue, returnType, webRequest);
        }
    }

从此处我们可以直接关注AbstractMessageConverterMethodProcessor#writeWithMessageConverters()方法

    protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
            ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
            throws IOException, HttpMediaTypeNotAcceptableException {

        Class<?> returnValueClass = returnValue.getClass();
        HttpServletRequest servletRequest = inputMessage.getServletRequest();
        // 大多用于获取请求包头的accept头,表明客户端需要接收什么类型的媒体类型
        List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
        // 优先应用@RequestMapping的produce属性,表示生产何种类型的媒体类型,否则则采用messageConverters集合下指定的supportMediaTypes属性集合
        List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);

        // 匹配查找结果
        Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
        for (MediaType requestedType : requestedMediaTypes) {
            for (MediaType producibleType : producibleMediaTypes) {
                if (requestedType.isCompatibleWith(producibleType)) {
                    compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
                }
            }
        }
        // 没有匹配的媒体类型处理,则抛异常
        if (compatibleMediaTypes.isEmpty()) {
            throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
        }

        List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
        MediaType.sortBySpecificityAndQuality(mediaTypes);

        ......
        ......

        if (selectedMediaType != null) {
            selectedMediaType = selectedMediaType.removeQualityValue();
            // 遍历消息处理器集合,统一通过canWrite()方法来做条件判断,采用write()方法写入数据
            for (HttpMessageConverter<?> messageConverter : this.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;
                }
            }
        }
        // 抛异常
        throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
    }
  1. 优先比较消息的媒体类型是否能被响应。不能被响应则会抛出异常
    • 请求体的媒体类型获取:Accept头、请求路径的文件后缀名等
    • 响应体的媒体类型获取:@RequestMapping注解属性produce(优先)、messageConverters配置的supportMediaTypes集合(其次)、所有类型均支持(默认)
  2. 写入响应体时,优先判断消息处理器是否支持返回内容对应的类,是则开始写入数据到响应体。此点多应用于json对象的返回包装,读者也可以多关注spring内置的MappingJackson2HttpMessageConverter消息处理器

  3. 上述条件均不满足的情况下,会抛出Could not find acceptable representation等错误信息

RequestMappingHandlerAdapter#getModelAndView()-判断是否需要返回视图对象

    private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
            ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

        modelFactory.updateModel(webRequest, mavContainer);
        // 请求如果已经标记为已处理,则返回null的视图对象。
        if (mavContainer.isRequestHandled()) {
            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;
    }

主要通过ModelAndViewContainer#requestHandled标记来判断是否返回视图对象,此标记为null表示不经过视图返回给前端而是通过其他形式的返回比如直接返回数据给前端,具体可看前面的代码分析。

总结

最好结合SpringMVC源码情操陶冶-DispatcherServlet简析(二)和SpringMVC源码情操陶冶-AnnotationDrivenBeanDefinitionParser注解解析器两篇博文来阅读,则会对HandlerAdapter适配器有更深的理解

编辑:乙乙北乙

发布时间:2018-11-13 09:25:56

当前文章:http://neomi.cn/wuxingquejinmushuihuotu/

大地信誉棋牌 集结号捕鱼外挂手机版 哪款棋牌游戏能赚钱 全民斗地主棋牌游戏 手机棋牌app论坛 四川皮皮麻将老版本 延边麻将官方下载 在蓝洞棋牌投诉电话

42655 90600 21471 65902 23973 1960439531 26174 88821

责任编辑:纯建安

随机推荐