SpringMVC源码分析-HandlerAdapter(3)-RequestMappingHandlerAdapter请求处理

RequestMappingHanderAdapter的请求处理

RequestMappingHanderAdapter处理请求的入口方法是handleInternal:

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    // 最终返回类型
    ModelAndView mav;
    // 检查请求类型和session支持
    checkRequest(request);

    // 执行请求的处理
    if (this.synchronizeOnSession) {//是否对Session同步
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // No HttpSession available -> no mutex necessary
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // No synchronization on session demanded at all...
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    // 给缓存设置过期时间
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        // 检查处理器是否有@SessionAttributes注解
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }
    }

    return mav;
}
我们可以看到处理请求的最终会返回一个ModelAndView的对象

checkRequest方法

checkRequest方法源码:

protected final void checkRequest(HttpServletRequest request) throws ServletException {
    // 根据supportedMethods属性判断是否支持当前请求的请求类型
    String method = request.getMethod();
    if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
        throw new HttpRequestMethodNotSupportedException(
                method, StringUtils.toStringArray(this.supportedMethods));
    }

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

根据supportedMethods属性判断是否支持当前请求的请求类型
那么supportedMethods属性是如何初始化的?

private Set<String> supportedMethods;
supportedMethods属性默认为空,可以在RequestMappingHandlerAdapter初始化时进行设置
public WebContentGenerator(boolean restrictDefaultSupportedMethods) {
    if (restrictDefaultSupportedMethods) {
        this.supportedMethods = new LinkedHashSet<String>(4);
        this.supportedMethods.add(METHOD_GET);
        this.supportedMethods.add(METHOD_HEAD);
        this.supportedMethods.add(METHOD_POST);
    }
    initAllowHeader();
}
如果在构造方法中为restrictDefaultSupportedMethods传true
supportedMethods只会支持GET,HEAD,POST三种请求
public AbstractHandlerMethodAdapter() {
    super(false);
}
AbstractHandlerMethodAdapter继承自WebContentGenerator
RequestMappingHandlerAdapter的父类AbstractHandlerMothodAdapter中
直接传入了false,默认不检查请求类型

getSessionAttributesHandler

getSessionAttributesHandler方法源码:

private SessionAttributesHandler getSessionAttributesHandler(HandlerMethod handlerMethod) {
    Class<?> handlerType = handlerMethod.getBeanType();
    SessionAttributesHandler sessionAttrHandler = this.sessionAttributesHandlerCache.get(handlerType);
    if (sessionAttrHandler == null) {
        synchronized (this.sessionAttributesHandlerCache) {
            sessionAttrHandler = this.sessionAttributesHandlerCache.get(handlerType);
            if (sessionAttrHandler == null) {
                sessionAttrHandler = new SessionAttributesHandler(handlerType, sessionAttributeStore);
                this.sessionAttributesHandlerCache.put(handlerType, sessionAttrHandler);
            }
        }
    }
    return sessionAttrHandler;
}

// 是否存在attributeNames或attributeTypes
public boolean hasSessionAttributes() {
    return (this.attributeNames.size() > 0 || this.attributeTypes.size() > 0);
}

sessionAttributesHandlerCache属性是一个new好的空集合

private final Map<Class<?>, SessionAttributesHandler> 
sessionAttributesHandlerCache = new ConcurrentHashMap<Class<?>, SessionAttributesHandler>(64);

首先根据handlerType到SessionAttributesHandler中查找SessionAttributesHandler
如果没有就创建出来添加进去,这里使用了一个双重校验锁并且使用了一种懒汉式的加载方式

这其中用又到了一个sessionAttributeStore属性


sessionAttributeStore属性

private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();

DefaultSessionAttributeStore实现了SessionAttributeStore接口

public class DefaultSessionAttributeStore implements SessionAttributeStore {
    private String attributeNamePrefix = "";

    public DefaultSessionAttributeStore() {
    }

    public void setAttributeNamePrefix(String attributeNamePrefix) {
        this.attributeNamePrefix = attributeNamePrefix != null?attributeNamePrefix:"";
    }

    public void storeAttribute(WebRequest request, String attributeName, Object attributeValue) {
        Assert.notNull(request, "WebRequest must not be null");
        Assert.notNull(attributeName, "Attribute name must not be null");
        Assert.notNull(attributeValue, "Attribute value must not be null");
        String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
        request.setAttribute(storeAttributeName, attributeValue, 1);
    }

    public Object retrieveAttribute(WebRequest request, String attributeName) {
        Assert.notNull(request, "WebRequest must not be null");
        Assert.notNull(attributeName, "Attribute name must not be null");
        String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
        return request.getAttribute(storeAttributeName, 1);
    }

    public void cleanupAttribute(WebRequest request, String attributeName) {
        Assert.notNull(request, "WebRequest must not be null");
        Assert.notNull(attributeName, "Attribute name must not be null");
        String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
        request.removeAttribute(storeAttributeName, 1);
    }

    protected String getAttributeNameInSession(WebRequest request, String attributeName) {
        return this.attributeNamePrefix + attributeName;
    }
}

从代码可以看到SessionAttributeStore属性并不是用来保存SessionAttribute参数的容器,
而是保存SessionAttribute的工具,SessionAttribute最终被保存在request中


设置缓存的过期时间

if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
    // 如果包含SessionAttributes注解,且有name或type属性
    if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
        // 设置缓存时间,cacheSecondsForSessionAttributeHandlers默认0
        applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
    }
    else {
        prepareResponse(response);
    }
}

// cacheSeconds>0设置缓存时间,cacheSeconds=0阻止缓存
protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds) {
    if (this.useExpiresHeader || !this.useCacheControlHeader) {
        // Deprecated HTTP 1.0 cache behavior, as in previous Spring versions
        if (cacheSeconds > 0) {
            cacheForSeconds(response, cacheSeconds);
        }
        else if (cacheSeconds == 0) {
            preventCaching(response);
        }
    }
    else {
        CacheControl cControl;
        if (cacheSeconds > 0) {
            cControl = CacheControl.maxAge(cacheSeconds, TimeUnit.SECONDS);
            if (this.alwaysMustRevalidate) {
                cControl = cControl.mustRevalidate();
            }
        }
        else if (cacheSeconds == 0) {
            cControl = (this.useCacheControlNoStore ? CacheControl.noStore() : CacheControl.noCache());
        }
        else {
            cControl = CacheControl.empty();
        }
        applyCacheControl(response, cControl);
    }
}

invokeHandlerMethod

invokeHandlerMethod是一个核心方法,他具体执行请求的处理

invokeHandlerMethod源码:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    // 使用request和response创建ServletWebRequest类型的webRequest
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {

        // 初始化三个变量
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        // 创建ModelAndViewContainer,用于保存Model和View
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        // 异步处理相关...
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        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 + "]");
            }
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }

        // 处理请求
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}
首先使用request和response创建ServletWebRequest类型的webRequest
    ArgumentResolve解析参数是用的request就是这个webRequest

然后,初始化三个变量WebDataBinderFactory,ModelFactory,ServletInvocableHandlerMethod

之后新建传递参数的,ModelAndViewContainer容器,执行请求,请求执行完成的后置处理

WebDataBinderFactory初始化

WebDataBinderFactory:

用于创建WebDataBinder

WebDataBinder:

用于参数绑定,实现参数和String之间的类型转换
ArgumentResolve进行参数解析的过程中会用到WebDataBinder
ModelFactory在更新Model是也会用到WebDataBinder

getDataBinderFactory源码:

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
    // 检查当前Handler中的InitBinder方法是否已经在缓存中
    Class<?> handlerType = handlerMethod.getBeanType();
    Set<Method> methods = this.initBinderCache.get(handlerType);
    // 如果没在缓存中,找到并设置到缓存
    if (methods == null) {
        methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
        this.initBinderCache.put(handlerType, methods);
    }
    // 保存initBinder方法的集合
    List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
    // 将所有符合条件的全局InitBinder方法添加到initBinderMethods
    for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
        if (entry.getKey().isApplicableToBeanType(handlerType)) {
            Object bean = entry.getKey().resolveBean();
            for (Method method : entry.getValue()) {
                initBinderMethods.add(createInitBinderMethod(bean, method));
            }
        }
    }
    // 将当前Handler中的InitBinder方法添加到initBinderMethods
    for (Method method : methods) {
        Object bean = handlerMethod.getBean();
        initBinderMethods.add(createInitBinderMethod(bean, method));
    }
    // 创建DataBinderFactory并返回,DataBinderFactory和InitBinder方法相关联
    return createDataBinderFactory(initBinderMethods);
}

protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
        throws Exception {

    return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}
WebDataBinderFactory的创建过程:
    找出符合条件的@InitBinder方法,
    使用它们创建ServletRequestDataBinderFactory类型的WebDataBinderFactory

InitBinder方法包含两部分:
    1,注释了@ControllerAdvice并且符合要求的全局处理器中的InitBinder方法
    (创建RequestMappingHandlerAdapter时已经设置到缓存)
    2,处理自身的InitBinder方法(第一次调用后保存到缓存中)
    添加顺序是先全局后自身

ModelFactory初始化

ModelFactory:

ModelFactory是用来处理Model的,有两个作用:
1,处理器处理前对Model进行初始化
2,处理完请求后对Model参数进行更新

Model初始化包含3部分:

1,将原来的SessionAttributes中的值设置到Model中
2,执行注视了@ModelAttribute的方法并将其值设置到model
3,处理器中注释了@ModelAttribute的参数如果同时也在SessionAttributes中配置了
而且在mavContainer中没有值,则从全部SessionAttributes中查找出并设置进去
(可能是其他处理器设置的值)

Model更新:

先对SessionAttributes进行设置
如果处理器调用了SessionStatus#setComplete,则清空SessionAttributes
否则将mavContainer中的defaultModel中响应参数设置到SessionAttributes
然后按需要给Model设置参数对应的BindingResult

getModelFactory源码:

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
    // 获取SessionAttributesHandler
    SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
    // 获取有@ModelAttribute没有@RequestMapping的方法,使用后添加到缓存
    Class<?> handlerType = handlerMethod.getBeanType();
    Set<Method> methods = this.modelAttributeCache.get(handlerType);
    if (methods == null) {
        methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
        this.modelAttributeCache.put(handlerType, methods);
    }
    List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
    // 先添加全局@ControllerAdvice方法,后添加当前处理器定义的@ModelAttribute方法
    for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
        if (entry.getKey().isApplicableToBeanType(handlerType)) {
            Object bean = entry.getKey().resolveBean();
            for (Method method : entry.getValue()) {
                attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
            }
        }
    }
    for (Method method : methods) {
        Object bean = handlerMethod.getBean();
        attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
    }

    // 创建ModelFactory
    return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);使用了3个参数
1,注释了@ModelAttribute的方法
    1)@ControllerAdvice类中定义的全局@ModelAttribute方法
    2)处理器自己的@ModelAttribute方法
    先添加全局,后添加自己的
2,WebDataBinderFactory,前面创建出来的
3,SessionAttributesHandler,由getSessionAttributesHandler获得

ServletInvocableHandlerMethod初始化

ServletInvocableHandlerMethod继承自HandlerMethod,并且可以直接执行
此方法就是情急请求的处理方法,参数绑定,请求处理,返回值处理都是在此方法中完成的

部分源码:

ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
    return new ServletInvocableHandlerMethod(handlerMethod);
}
首先使用handlerMethod新建了一个ServletInvocableHandlerMethod类
然后设置argumentResolvers,returnValueHandlers,binderFactory,parameterNameDiscoverer

ModelAndViewContainer初始化

ModelAndViewContainer用于保存Model和View

部分源码:

// 创建ModelAndViewContainer用于保存Model和View
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 将FlashMap中的数据设置到Model
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 使用modelFactory将SessionAttributes和注释了@ModelAttributede的方法的参数设置到Model
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
// 根据配置对ignoreDefaultModelOnRedirect进行设置
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
ModelAndViewContainer贯穿于整个处理过程,对mavContainer设置了3部分内容:
1,将FlashMap中的数据设置到Model
2,使用modelFactory将SessionAttributes和注释了@ModelAttributede的方法的参数设置到Model
3,根据配置对ignoreDefaultModelOnRedirect进行设置
public void initModel(NativeWebRequest request, ModelAndViewContainer container,
        HandlerMethod handlerMethod) throws Exception {

    Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
    container.mergeAttributes(sessionAttributes);
    invokeModelAttributeMethods(request, container);

    for (String name : findSessionAttributeArguments(handlerMethod)) {
        if (!container.containsAttribute(name)) {
            Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
            if (value == null) {
                throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
            }
            container.addAttribute(name, value);
        }
    }
}

invokeAndHandler执行请求

invocableMethod.invokeAndHandle(webRequest, mavContainer);

直接调用了ServletInvocableHandlerMethod#invokeAndHandle方法执行请求,后续这部分会详细分析


getModelAndView请求处理完成后的后置处理

相关源码:

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

    // 调用updateModel更新Model(设置了SessionAttributes和给Model设置BindingResult)
    modelFactory.updateModel(webRequest, mavContainer);
    if (mavContainer.isRequestHandled()) {
        return null;
    }

    // 根据mavContainer创建ModelAndView
    ModelMap model = mavContainer.getModel();
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
    if (!mavContainer.isViewReference()) {
        mav.setView((View) mavContainer.getView());
    }

    // 如果model是RedirectAttributes类型,将值设置到FlashMap
    if (model instanceof RedirectAttributes) {
        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
    }
    return mav;
}

一共做了3件事:

调用updateModel更新Model(设置了SessionAttributes和给Model设置BindingResult)
根据mavContainer创建ModelAndView
如果model是RedirectAttributes类型,将值设置到FlashMap

这里的model只有在处理器返回redirect类型的视图是才能是RedirectAttributes类型
在不返回redirect类型视图的处理器中,
即使使用RedirectAttributes设置了变量也不会保存到FlashMap

这部分会在ModelAndViewContainer时详细分析...

到这里整个RequestMappingHandlerAdapter处理请求的过程就分析完了
还有很多内部组件我们并没有分析到,接下来我们就一一进行分析

猜你喜欢

转载自blog.csdn.net/abap_brave/article/details/80956261
今日推荐