002-Spring MVC流程解析

前言

实际上我们的001-Spring Boot HelloWorld就是Spring boot实现的springMVC Helloworld代码。

DispatcherServlet

Spring MVC中所有的请求都有DispatcherServlet来负责分发处理。当然需要很多相关的组件。

java配置方式注册DispatcherServlet

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class);

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

web.xml配置

<web-app>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/app-context.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>

</web-app>

以上两种方式是在不使用Spring boot时的注册方式。

使用Spring boot的方式

其实我们的Spring Boot HelloWorld一章就是使用的该方式,Spring Boot 遵循不同的初始化顺序。Spring Boot 没有钩入 Servlet 容器的生命周期,而是使用 Spring 配置来引导自身和嵌入式 Servlet 容器。

相关组件

在org.springframework.web.servlet.DispatcherServlet源码中有如下初始化方法

    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);
    }

其分别注册了如下Spring MVC的相关组件,其中最重要的是HandlerMapping和HandlerAdapter

说明
HandlerMappingHandlerMapping有多个实现,在DispatcherServlet也是以集合的形式存在,意味着同一个请求可能会有多个HandlerMapping来处理,我们的SpringMVC的拦截器也是通过HandlerMapping映射到处理逻辑的。RequestMappingHandlerMapping是最常用的一个实现,支持带@RequestMapping注释的方法。返回HandlerExecutionChain对象
HandlerAdapter处理请求逻辑,返回ModelAndView对象
LocaleResolver解析墙角客户端可能的时区,以便能提供国际化的视图。
ViewResolver视图解析器,将ModelAndView对象,解析为View对象。
MultipartResolver解析多不分请求(如:表单中的文件上传)等。
HandlerExceptionResolver异常解析器。

HandlerMapping

DispatcherServlet的initHandlerMappings(context);方法源码如下:

    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
            Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        } else {
            try {
                HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            } catch (NoSuchBeanDefinitionException var4) {
            }
        }

        if (this.handlerMappings == null) {
            this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

        Iterator var6 = this.handlerMappings.iterator();

        while(var6.hasNext()) {
            HandlerMapping mapping = (HandlerMapping)var6.next();
            if (mapping.usesPathPatterns()) {
                this.parseRequestPath = true;
                break;
            }
        }

    }

spring boot在使用mvc的时候,默认注册了几个HandlerMapping
在这里插入图片描述
注意顺序,源码中用了sort方法排序的。

HandlerMapping接口定义的方法如下

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

HandlerMapping返回了一个HandlerExecutionChain(执行器链)对象,该对象包含两个重要属性,一个是handler(Object类型)对象,一个是拦截器集合(List<HandlerInterceptor>)。

handler是Object类型,名义上他可以是任意类型,通过它我们可以确定到底用哪一个HandlerAdapter(处理适配器)RequestMappingHandler对应的handler对象是HandlerMethod。通过HandlerMethod我们可以找到对应的HandlerAdapter实际处理类。

在每个请求执行的时候会执行如下DispatcherServlet方法

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }

DispatcherServlet通过当前的请求对象request遍历我们初始化的HandlerMapping集合,以获取对应的HandlerExecutionChain对象。

HandleAdapter

DispatcherServlet的initHandlerAdapters(context);方法源码如下:

	private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
				// We keep HandlerAdapters in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}

		// Ensure we have at least some HandlerAdapters, by registering
		// default HandlerAdapters if no other adapters are found.
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

Spring boot默认添加了如下4种HandlerAdapter
在这里插入图片描述

HandleAdapter接口定义如下

public interface HandlerAdapter {
    boolean supports(Object hanlder);

    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);
}

supports方法接受的就是HandlerExecutionChain的handler对象。比如,我们的示例返回的是HandlerMethod,HandlerMethod对应的是RequestMappingHandlerAdapter。

HandlerAdapter 的handle方法返回一个ModelAndView对象,其包含了数据模型和页面视图名称。

HandlerMethod实际上就是我们@RequestMapping注解的方法,它包含了@RequestMapping注解的方法的所有信息(方法名称、参数等等)。而我们@RequestMapping注解的方法实际上就是HandlerAdapter执行的。

ViewResolver

ViewResolver在SpringMVC中就是一种策略模式的实现。根据不同的实现类实现支持不同的视图。比如我们要支持freemarker,那么需要我们手动配置FreeMarkerViewResolver到Spring 容器
SpringBoot默认加载的视图解析器
在这里插入图片描述

总结

SpringMVC 主要的组件工作流程如下

在这里插入图片描述

关于ViewResolver本章介绍得很少,我们后续会讲到。

上一篇:001-Spring Boot HelloWorld
下一篇:003-Spring MVC URL映射与参数绑定

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值