Spring MVC初始化

Spring MVC初始化

经过上一篇分析请求的处理,可以得出spring MVC的请求处理过程中需要的组件,从而才知道初始化的时候需要哪些;

因为是基于spring 的,所以需要加载spring 容器,并且组件都由spring容器进行管理

所以初始化分为两部分:
* spring容器;
* spring MVC 即DispatcherServlet类中的属性;

调用流程
  • HttpServletBean init()
  • HttpServletBean init() 中调用了子类 FrameworkServlet 的 initServletBean() 方法
  • FrameworkServlet 的 initServletBean() 中调用了 initWebApplicationContext() 初始化webApplicationContext(FrameworkServlet的全局变量) spring上下文(容器)
  • FrameworkServlet 的 initServletBean() 中调用了 initFrameworkServlet() 方法为空
  • DispatcherServlet 的 onRefresh() 方法, spring 容器初始化完成,将applicationContext 对象传进 DispatcherServlet
  • DispatcherServlet 的 initStrategies(ApplicationContext context); 方法
DispatcherServlet 的 onRefresh() 方法,源码:
    protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }
DispatcherServlet 的 initStrategies(ApplicationContext context); 源码:
    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

如果熟悉请求处理流程,可以直接根据方法名清楚这些初始化的组件;

initHandlerMappings(context) 方法

此部分源码初始化逻辑有点难,但是结果清晰。

原理:

1.将 url字符串 与 controller中的method 加入到 map 集合中
2. 将 拦截器配置的拦截器 加载到 集合中(HandlerExecutionChain 中有拦截器链 HandlerInterceptor[] interceptors )
以至于最后能够通过url 匹配快速定位获取到 HandlerExecutionChain 类,
结果: 最后初始化 HandlerMappings 用来获取 HandlerExecutionChain

断点进入
initHandlerMappings 代码:

/** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. */
    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        // 默认 detectAllHandlerMappings =true 则进入判断
        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            //翻译 : 查找出所有应用中的HandlerMappings 类,包括祖先
            /* matchingBeans 结果 通过打断点 得出两个 HandlerMapping 类 (都是从spring 容器获取,已经实例化) 1. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 2. org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping 处理请求时 ,是遍历 handlerMappings 取符合的第一个 HandlerMapping 类 HandlerMapping 初始化时,将所有的 interceptors 与 handler 加载出来 */ 
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                OrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }

initHandlerAdapters(context);

初始化
* RequestMappingHandlerAdapter
* HttpRequestHandlerAdapter
* SimpleControllerHandlerAdapter

都继承 AbstractHandlerMethodAdapter 类,其中用模板方法模式,控制子类实现 两个方法 supportsInternal()handleInternal() 方法
AbstractHandlerMethodAdapter 通过 supports() 与 handle() 调用 supportsInternal() 与 handleInternal()

部分代码块:

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {

    @Override
    public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }

    @Override
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        return handleInternal(request, response, (HandlerMethod) handler);
    }

}

AbstractHandlerMethodAdapter 实现 HandlerAdapter 接口


public interface HandlerAdapter {

    /** 用来判断 HandlerExecutionChain 的 handler 属性是否支持,若是支持即当前的 HandlerAdapter实现类就是request的处理类 */
    boolean supports(Object handler);

    /* 处理请求的方法 */
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);

}

RequestMappingHandlerAdapter
初始化后调用 afterPropertiesSet() 方法(因为实现了InitializingBean接口具体看spring 生命周期)
代码块:



 @Override public void afterPropertiesSet() { // Do this first, it may add ResponseBody advice beans initControllerAdviceCache(); if (this.argumentResolvers == null) { //mark  List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.initBinderArgumentResolvers == null) { //mark  List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) { /* 加载默认返回值处理器, 这部分涉及配置 <mvc:annotation-driven > <mvc:message-converters register-defaults="true"> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> message-converters 组件来处理从controller 返回的结果,比如502错误(需要jackson转map成json格式)、或者进行字符格式转换 只处理 responseBody 注解的返回值 RequestResponseBodyMethodProcessor 类处理 */ List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } } 

initHandlerExceptionResolvers 方法,初始化异常解决处理器

简单异常处理类
SimpleMappingExceptionResolver
继承 AbstractHandlerExceptionResolver
实现 doResolveException
AbstractHandlerExceptionResolver 类中通过模板方法模式,resolveException() 方法中 调用子类实现的 doResolveException 处理请求

通过在spring 中配置继承 AbstractHandlerExceptionResolver 的bean 可以注册自定义异常处理类

    <bean id="appHandlerExceptionResolver" class="com.java.exception.resolvers.AppHandlerExceptionResolver" >
    </bean>

AppHandlerExceptionResolver 类

/* 在这个处理类中可以定制个性化的异常返回视图,以及异常json结果 */
public class AppHandlerExceptionResolver extends AbstractHandlerExceptionResolver {

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        // TODO Auto-generated method stub

        ModelAndView exView=new ModelAndView("exception");
        exView.addObject("exception", ex);
        response.setStatus(500);


        return exView;
    }

}

initViewResolvers(context) 初始化视图处理器

springMVC配置的jsp视图解释器 InternalResourceViewResolver 的结构

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp" />
    </bean>

InternalResourceViewResolver
继承 UrlBasedViewResolver 类
继承 AbstractCachingViewResolver 类
实现 ViewResolver 接口
最终通过 resolveViewName() 方法返回 org.springframework.web.servlet.View 视图对象

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/zjs40/article/details/60479057
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞