SpringMVC实现原理解析

技术SpringMVC实现原理解析 SpringMVC实现原理解析一、SpringMVC简介
SpringMVC是一种基于Spring实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使用了

SpringMVC实现原理分析

一、SpringMVC简介

SpringMVC是基于Spring的轻量级web框架,实现了请求驱动型的Web MVC设计模式。它利用MVC架构模式的思想,将Web层的职责进行解耦,管理应用所需对象的生命周期,为简化日常开发提供了极大的便利。

二、SpringMVC核心组件

DispatcherServlet:统一调度其他组件调用的中央控制器,是整个请求响应的控制中心,本质上是一个servlet

处理程序:业务处理器,处理客户的具体请求,返回处理结果,通常以各种Controller的形式;

HandlerMapping:处理器映射器,客户端请求URL和服务处理器之间的映射关系,根据请求URL可以找到对应的服务处理器;

HandlerAdapter:处理器适配器负责调用业务处理器的具体方法,返回逻辑视图ModelAndView对象;

视图解析器:视图解析器,负责将业务处理器返回的ModelAndView对象解析成JSP;

三、SpringMVC工作流程

1.客户端发送请求,所有请求都由中央处理器DispatcherServlet处理;

2.DispatcherServlet通过处理器映射器HandlerMapping根据客户端请求URL获取对应的业务处理器Handler对象;

3.DispatcherServlet调用HandlerAdapter处理器适配器,通知HandlerAdapter执行哪个处理程序;

4.HandlerAdapter调用特定处理程序(控制器)的方法,获取返回的结果ModelAndView,并将结果返回DispatcherServlet;

5.DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真实视图;

6.DispatcherServlet将模型数据填充到视图中;

7.DispatcherServlet向用户响应结果。

四、SpringMVC流程图

五、SpringMVC源码解析

5.1、SpringMVC启动流程

SpringMVC首先需要从web.xml中配置DispatcherServlet,如下所示:

小型应用程序

servlet-name spring MVC/servlet-name

servlet-class org . spring framework . web . servlet . dispatchersvlet/servlet-class

启动时加载1/启动时加载

初始化参数

param-name contextconfiglocation/param-name

param-value class path * : pringmvc . XML/param-value

/init-param

/servlet

servlet映射

servlet-name spring MVC/servlet-name

url模式//url模式

/servlet-映射

根据servlet的相关知识,所有的请求都会交给Dispatcher servlet进行处理,项目启动时会创建DispatcherServlet并执行DispatcherServlet的初始化init方法。

DispatcherServlet继承的FrameworkServlet、FrameworkServlet继承的httpersvletbean、httpersvletbean实现了HttpServlet的init方法,实际实现的是initServletBean方法,由FrameworkServlet子类重写。

FrameworkServlet重写initServletBean方法的实现逻辑如下:

1个受保护的最终void initServletBean()引发ServletException {

2尝试{

3 /** 1.初始化Spring Web容器*/

4 this . webapplicationcontext=initWebApplicationContext();

5 /** 2.初始化框架Servlet,清空方法,并将其交给子类扩展*/

6 initFrameworkServlet();

7 }

8个catch(ServletException | runtimeexcepo

n ex) {
9 logger.error("Context initialization failed", ex);
10 throw ex;
11 }
12 }

protected WebApplicationContext initWebApplicationContext() {
        /** 1. 尝试获取WebApplicationContext */
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            wac = findWebApplicationContext();
        }
        /** 2.如果当前没有WebApplicationContext就初始化并刷新WebApplicationContext */
        if (wac == null) {
            wac = createWebApplicationContext(rootContext);
        }
        if (!this.refreshEventReceived) {
            synchronized (this.onRefreshMonitor) {
                /** 3.WebApplicationContext初始化并刷新后,执行onRefresh方法*/
                onRefresh(wac);
            }
        }
        if (this.publishContext) {
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }

通过createWebApplicationContext方法创建IOC容器WebApplicationContext并启动刷新容器,当Spring容器启动后再执行onRefresh方法刷新Servlet,Spring容器启动刷新逻辑不再细看,onRefresh方法实际是交给了

子类DispatcherServlet实现,DispatcherServlet的onRefresh方法源码如下:

/** DispatcherServlet onRefresh方法 */
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }
    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        /** 初始化处理器映射器HandlerMapping */
        initHandlerMappings(context);
        /** 初始化处理器适配器handlerAdapter */
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        /** 初始化视图解析器ViewResolver */
        initViewResolvers(context);
        initFlashMapManager(context);
    }

可以看出onRefresh方法主要是初始化相关组件,如初始化业务处理器映射器HandlerMapping、处理器适配器HandlerAdapter、视图解析器ViewResolver等,这里着重分析HandlerMapping和HandlerAdapter的初始化。

5.1.1、处理器映射器初始化

首先看处理器映射器的初始化,方法为DispatcherServlet的initHandlerMapping(ApplicationContext context), 源码如下:

 1 /** 初始化处理器映射器 */
 2     private void initHandlerMappings(ApplicationContext context) {
 3         this.handlerMappings = null;
 4         /** 1.先尝试从Spring容器中获取所有HandlerMapping s*/
 5         if (this.detectAllHandlerMappings) {
 6             MapString, HandlerMapping matchingBeans =
 7                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
 8             if (!matchingBeans.isEmpty()) {
 9                 this.handlerMappings = new ArrayList(matchingBeans.values());
10                 AnnotationAwareOrderComparator.sort(this.handlerMappings);
11             }
12         }
13         else {
14             try {
15                 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
16                 this.handlerMappings = Collections.singletonList(hm);
17             }
18             catch (NoSuchBeanDefinitionException ex) {
19             }
20         }
21 
22         /** 2.如果Spring容器中没有HandlerMapping,那么就初始化默认的HandlerMapping*/
23         if (this.handlerMappings == null) {
24             // 初始化默认HandlerMapping
25             this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
26         }
27     }
28 
29     /** 获取默认策略 */
30     protected T ListT getDefaultStrategies(ApplicationContext context, ClassT strategyInterface) {
31         String key = strategyInterface.getName();
32         /** 1.从配置文件中获取默认策略
33          *  配置文件为DispatcherServlet.properties
34          *  key为策略类全路径
35          * */
36         String value = defaultStrategies.getProperty(key);
37         if (value != null) {
38             String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
39             ListT strategies = new ArrayList(classNames.length);
40             for (String className : classNames) {
41                 try {
42                     /** 2.反射初始化所有策略实例*/
43                     Class clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
44                     Object strategy = createDefaultStrategy(context, clazz);
45                     strategies.add((T) strategy);
46                 }
47                 catch (ClassNotFoundException ex) {
48                 }
49                 catch (LinkageError err) {
50                 }
51             }
52             return strategies;
53         }
54         else {
55             return new LinkedList();
56         }
57     }

首先尝试从Spring容器中获取所有HandlerMapping的bean,如果不存在就加载默认处理器映射器,getDefaultStrategies方法是从配置文件DispatcherServlet.properties中加载默认配置,配置文件内容如下:

 1 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
 2 
 3 org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
 4 
 5 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
 6     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
 7     org.springframework.web.servlet.function.support.RouterFunctionMapping
 8 
 9 org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
10     org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
11     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
12     org.springframework.web.servlet.function.support.HandlerFunctionAdapter
13 
14 
15 org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
16     org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
17     org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
18 
19 org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
20 
21 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
22 
23 org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

可以发现默认HandlerMapping为BeanNameUrlHandlerMapping、RequestMappingHandlerMapping和RouterFunctionMapping,以RequestMappingHandlerMapping为例,实现了InitializingBean,

所以初始化后会执行afterPropertiesSet方法,该方法初始化属性,并调用父类AbstractHandlerMapping的afterPropertiesSet方法,该方法又执行了方法initHandlerMethods方法,AbstractHandlerMapping的

initHandlerMethods方法实质就是初始化方法映射的方法,逻辑如下:

/** 初始化路径和方法映射 */
    protected void initHandlerMethods() {
        /** 1.遍历Spring容器中所有的bean */
        for (String beanName : getCandidateBeanNames()) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                /** 2.处理所有后续的bean */
                processCandidateBean(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }
    protected void processCandidateBean(String beanName) {
        Class beanType = null;
        try {
            /** 1.获取bean的Class对象 */
            beanType = obtainApplicationContext().getType(beanName);
        }
        catch (Throwable ex) {
        }
        /** 2.调用isHandler方法判断该bean是否是业务处理器*/
        if (beanType != null  isHandler(beanType)) {
            /** 2.寻找业务处理器中映射方法 */
            detectHandlerMethods(beanName);
        }
    }
    /** 判断bean是否是业务处理器( 被Controller或RequestMapping注解修饰 )*/
    protected boolean isHandler(Class beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

遍历Spring容器中所有的bean,判断bean中是否包含@Controller或@RequestMapping注解,如果包含那么就是业务处理器,那么就执行detectHandlerMethods方法处理,该方法逻辑如下:

protected void detectHandlerMethods(Object handler) {
        /** 1.获取处理器Class对象 */
        Class handlerType = (handler instanceof String 
                obtainApplicationContext().getType((String) handler) : handler.getClass());
        if (handlerType != null) {
            Class userType = ClassUtils.getUserClass(handlerType);
            /** 2.寻找所有映射方法集合,存入MapMethod,RequestMappingInfo中
             *  RequestMappingInfo就是方法映射关系类 */
            MapMethod, T methods = MethodIntrospector.selectMethods(userType,
                    (MethodIntrospector.MetadataLookupT) method - {
                        try {
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    });
            methods.forEach((method, mapping) - {
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                /** 注册处理器、方法、映射关系, 缓存在MappingRegistry实例的Map中 */
                registerHandlerMethod(handler, invocableMethod, mapping);
            });
        }
    }

先从业务处理器中寻找所有映射方法封装成映射关系实例,然后将处理器、方法和映射关系实例注册到MappingRegistry实例中。

5.1.2、处理器适配器初始化

处理器适配器HandlerAdapter的初始化过程和处理器映射器HandlerMapping的初始化过程如出一辙,最终落实到默认的适配器RequestMappingHandlerAdapter的初始化,最终是重写了afterPropertiesSet方法。

5.2、SpringMVC工作流程

------------恢复内容开始------------

一、SpringMVC简介

SpringMVC是一种基于Spring实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,并管理应用所需对象的生命周期,为简化日常开发,提供了很大便利。

二、SpringMVC核心组件

DispatcherServlet:中央控制器,统一调度其他组件的调用,是整个请求响应的控制中心,本质是一个Servlet;

Handler:业务处理器,处理客户端的具体请求和返回处理结果,通常存在形式就是各种Controller;

HandlerMapping:处理器映射器,客户端请求URL和业务处理器的映射关系,根据请求URL可以找到对应的业务处理器;

HandlerAdapter:处理器适配器,负责调用业务处理器的具体方法,返回逻辑视图ModelAndView对象;

ViewResolver:视图解析器,负责将业务处理器返回的视图ModelAndView对象解析成JSP;

三、SpringMVC工作流程

1、客户端发送请求,所有请求都有中央处理器DispatcherServlet处理;

2、DispatcherServlet通过处理器映射器HandlerMapping根据客户端请求URL获取对应的业务处理器Handler对象;

3、DispatcherServlet调用HandlerAdapter处理器适配器,通知HandlerAdapter执行具体哪个Handler;

4、HandlerAdapter调用具体Handler(Controller)的方法并得到返回的结果ModelAndView,且将结果返回给DispatcherServlet;

5、DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图;

6、DispatcherServlet将模型数据填充到视图中;

7、DispatcherServlet将结果响应给用户。

四、SpringMVC流程图

五、SpringMVC源码解析

5.1、SpringMVC启动流程

SpringMVC首先需要从web.xml配置DispatcherServlet,如下:

servlet
     servlet-namespringmvc/servlet-name
     servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class
      load-on-startup1/load-on-startup
      init-param
            param-namecontextConfigLocation/param-name
            param-valueclasspath*:springmvc.xml/param-value
      /init-param
/servlet
servlet-mapping
     servlet-namespringmvc/servlet-name
     url-pattern//url-pattern
/servlet-mapping

根据servlet相关知识可知所有请求都会交给DispatcherServlet处理,并且项目启动时会创建DispatcherServlet并会执行DispatcherServlet的初始化init方法。

DispatcherServlet继承之FrameworkServlet,FrameworkServlet继承之HttpServletBean,HttpServletBean实现了HttpServlet的init方法,实际是执行了initServletBean方法,该方法被子类FrameworkServlet重写,

FrameworkServlet重写initServletBean方法实现逻辑如下:

 1 protected final void initServletBean() throws ServletException {
 2         try {
 3             /** 1.初始化Spring Web容器*/
 4             this.webApplicationContext = initWebApplicationContext();
 5             /** 2.初始化框架Servlet,空方法,交给子类扩展*/
 6             initFrameworkServlet();
 7         }
 8         catch (ServletException | RuntimeException ex) {
 9             logger.error("Context initialization failed", ex);
10             throw ex;
11         }
12     }
protected WebApplicationContext initWebApplicationContext() {
        /** 1. 尝试获取WebApplicationContext */
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            wac = findWebApplicationContext();
        }
        /** 2.如果当前没有WebApplicationContext就初始化并刷新WebApplicationContext */
        if (wac == null) {
            wac = createWebApplicationContext(rootContext);
        }
        if (!this.refreshEventReceived) {
            synchronized (this.onRefreshMonitor) {
                /** 3.WebApplicationContext初始化并刷新后,执行onRefresh方法*/
                onRefresh(wac);
            }
        }
        if (this.publishContext) {
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }

通过createWebApplicationContext方法创建IOC容器WebApplicationContext并启动刷新容器,当Spring容器启动后再执行onRefresh方法刷新Servlet,Spring容器启动刷新逻辑不再细看,onRefresh方法实际是交给了

子类DispatcherServlet实现,DispatcherServlet的onRefresh方法源码如下:

/** DispatcherServlet onRefresh方法 */
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }
    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        /** 初始化处理器映射器HandlerMapping */
        initHandlerMappings(context);
        /** 初始化处理器适配器handlerAdapter */
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        /** 初始化视图解析器ViewResolver */
        initViewResolvers(context);
        initFlashMapManager(context);
    }

可以看出onRefresh方法主要是初始化相关组件,如初始化业务处理器映射器HandlerMapping、处理器适配器HandlerAdapter、视图解析器ViewResolver等,这里着重分析HandlerMapping和HandlerAdapter的初始化。

5.1.1、处理器映射器初始化

首先看处理器映射器的初始化,方法为DispatcherServlet的initHandlerMapping(ApplicationContext context), 源码如下:

 1 /** 初始化处理器映射器 */
 2     private void initHandlerMappings(ApplicationContext context) {
 3         this.handlerMappings = null;
 4         /** 1.先尝试从Spring容器中获取所有HandlerMapping s*/
 5         if (this.detectAllHandlerMappings) {
 6             MapString, HandlerMapping matchingBeans =
 7                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
 8             if (!matchingBeans.isEmpty()) {
 9                 this.handlerMappings = new ArrayList(matchingBeans.values());
10                 AnnotationAwareOrderComparator.sort(this.handlerMappings);
11             }
12         }
13         else {
14             try {
15                 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
16                 this.handlerMappings = Collections.singletonList(hm);
17             }
18             catch (NoSuchBeanDefinitionException ex) {
19             }
20         }
21 
22         /** 2.如果Spring容器中没有HandlerMapping,那么就初始化默认的HandlerMapping*/
23         if (this.handlerMappings == null) {
24             // 初始化默认HandlerMapping
25             this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
26         }
27     }
28 
29     /** 获取默认策略 */
30     protected T ListT getDefaultStrategies(ApplicationContext context, ClassT strategyInterface) {
31         String key = strategyInterface.getName();
32         /** 1.从配置文件中获取默认策略
33          *  配置文件为DispatcherServlet.properties
34          *  key为策略类全路径
35          * */
36         String value = defaultStrategies.getProperty(key);
37         if (value != null) {
38             String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
39             ListT strategies = new ArrayList(classNames.length);
40             for (String className : classNames) {
41                 try {
42                     /** 2.反射初始化所有策略实例*/
43                     Class clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
44                     Object strategy = createDefaultStrategy(context, clazz);
45                     strategies.add((T) strategy);
46                 }
47                 catch (ClassNotFoundException ex) {
48                 }
49                 catch (LinkageError err) {
50                 }
51             }
52             return strategies;
53         }
54         else {
55             return new LinkedList();
56         }
57     }

首先尝试从Spring容器中获取所有HandlerMapping的bean,如果不存在就加载默认处理器映射器,getDefaultStrategies方法是从配置文件DispatcherServlet.properties中加载默认配置,配置文件内容如下:

 1 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
 2 
 3 org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
 4 
 5 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
 6     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
 7     org.springframework.web.servlet.function.support.RouterFunctionMapping
 8 
 9 org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
10     org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
11     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
12     org.springframework.web.servlet.function.support.HandlerFunctionAdapter
13 
14 
15 org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
16     org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
17     org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
18 
19 org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
20 
21 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
22 
23 org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

可以发现默认HandlerMapping为BeanNameUrlHandlerMapping、RequestMappingHandlerMapping和RouterFunctionMapping,以RequestMappingHandlerMapping为例,实现了InitializingBean,

所以初始化后会执行afterPropertiesSet方法,该方法初始化属性,并调用父类AbstractHandlerMapping的afterPropertiesSet方法,该方法又执行了方法initHandlerMethods方法,AbstractHandlerMapping的

initHandlerMethods方法实质就是初始化方法映射的方法,逻辑如下:

/** 初始化路径和方法映射 */
    protected void initHandlerMethods() {
        /** 1.遍历Spring容器中所有的bean */
        for (String beanName : getCandidateBeanNames()) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                /** 2.处理所有后续的bean */
                processCandidateBean(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }
    protected void processCandidateBean(String beanName) {
        Class beanType = null;
        try {
            /** 1.获取bean的Class对象 */
            beanType = obtainApplicationContext().getType(beanName);
        }
        catch (Throwable ex) {
        }
        /** 2.调用isHandler方法判断该bean是否是业务处理器*/
        if (beanType != null  isHandler(beanType)) {
            /** 2.寻找业务处理器中映射方法 */
            detectHandlerMethods(beanName);
        }
    }
    /** 判断bean是否是业务处理器( 被Controller或RequestMapping注解修饰 )*/
    protected boolean isHandler(Class beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

遍历Spring容器中所有的bean,判断bean中是否包含@Controller或@RequestMapping注解,如果包含那么就是业务处理器,那么就执行detectHandlerMethods方法处理,该方法逻辑如下:

protected void detectHandlerMethods(Object handler) {
        /** 1.获取处理器Class对象 */
        Class handlerType = (handler instanceof String 
                obtainApplicationContext().getType((String) handler) : handler.getClass());
        if (handlerType != null) {
            Class userType = ClassUtils.getUserClass(handlerType);
            /** 2.寻找所有映射方法集合,存入MapMethod,RequestMappingInfo中
             *  RequestMappingInfo就是方法映射关系类 */
            MapMethod, T methods = MethodIntrospector.selectMethods(userType,
                    (MethodIntrospector.MetadataLookupT) method - {
                        try {
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    });
            methods.forEach((method, mapping) - {
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                /** 注册处理器、方法、映射关系, 缓存在MappingRegistry实例的Map中 */
                registerHandlerMethod(handler, invocableMethod, mapping);
            });
        }
    }

先从业务处理器中寻找所有映射方法封装成映射关系实例,然后将处理器、方法和映射关系实例注册到MappingRegistry实例中。

5.1.2、处理器适配器初始化

处理器适配器HandlerAdapter的初始化过程和处理器映射器HandlerMapping的初始化过程如出一辙,最终落实到默认的适配器RequestMappingHandlerAdapter的初始化,最终是重写了afterPropertiesSet方法。

5.2、SpringMVC工作流程

------------恢复内容结束------------

------------恢复内容开始------------

一、SpringMVC简介

SpringMVC是一种基于Spring实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,并管理应用所需对象的生命周期,为简化日常开发,提供了很大便利。

二、SpringMVC核心组件

DispatcherServlet:中央控制器,统一调度其他组件的调用,是整个请求响应的控制中心,本质是一个Servlet;

Handler:业务处理器,处理客户端的具体请求和返回处理结果,通常存在形式就是各种Controller;

HandlerMapping:处理器映射器,客户端请求URL和业务处理器的映射关系,根据请求URL可以找到对应的业务处理器;

HandlerAdapter:处理器适配器,负责调用业务处理器的具体方法,返回逻辑视图ModelAndView对象;

ViewResolver:视图解析器,负责将业务处理器返回的视图ModelAndView对象解析成JSP;

三、SpringMVC工作流程

1、客户端发送请求,所有请求都有中央处理器DispatcherServlet处理;

2、DispatcherServlet通过处理器映射器HandlerMapping根据客户端请求URL获取对应的业务处理器Handler对象;

3、DispatcherServlet调用HandlerAdapter处理器适配器,通知HandlerAdapter执行具体哪个Handler;

4、HandlerAdapter调用具体Handler(Controller)的方法并得到返回的结果ModelAndView,且将结果返回给DispatcherServlet;

5、DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图;

6、DispatcherServlet将模型数据填充到视图中;

7、DispatcherServlet将结果响应给用户。

四、SpringMVC流程图

五、SpringMVC源码解析

5.1、SpringMVC启动流程

SpringMVC首先需要从web.xml配置DispatcherServlet,如下:

servlet
     servlet-namespringmvc/servlet-name
     servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class
      load-on-startup1/load-on-startup
      init-param
            param-namecontextConfigLocation/param-name
            param-valueclasspath*:springmvc.xml/param-value
      /init-param
/servlet
servlet-mapping
     servlet-namespringmvc/servlet-name
     url-pattern//url-pattern
/servlet-mapping

根据servlet相关知识可知所有请求都会交给DispatcherServlet处理,并且项目启动时会创建DispatcherServlet并会执行DispatcherServlet的初始化init方法。

DispatcherServlet继承之FrameworkServlet,FrameworkServlet继承之HttpServletBean,HttpServletBean实现了HttpServlet的init方法,实际是执行了initServletBean方法,该方法被子类FrameworkServlet重写,

FrameworkServlet重写initServletBean方法实现逻辑如下:

 1 protected final void initServletBean() throws ServletException {
 2         try {
 3             /** 1.初始化Spring Web容器*/
 4             this.webApplicationContext = initWebApplicationContext();
 5             /** 2.初始化框架Servlet,空方法,交给子类扩展*/
 6             initFrameworkServlet();
 7         }
 8         catch (ServletException | RuntimeException ex) {
 9             logger.error("Context initialization failed", ex);
10             throw ex;
11         }
12     }
protected WebApplicationContext initWebApplicationContext() {
        /** 1. 尝试获取WebApplicationContext */
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            wac = findWebApplicationContext();
        }
        /** 2.如果当前没有WebApplicationContext就初始化并刷新WebApplicationContext */
        if (wac == null) {
            wac = createWebApplicationContext(rootContext);
        }
        if (!this.refreshEventReceived) {
            synchronized (this.onRefreshMonitor) {
                /** 3.WebApplicationContext初始化并刷新后,执行onRefresh方法*/
                onRefresh(wac);
            }
        }
        if (this.publishContext) {
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }

通过createWebApplicationContext方法创建IOC容器WebApplicationContext并启动刷新容器,当Spring容器启动后再执行onRefresh方法刷新Servlet,Spring容器启动刷新逻辑不再细看,onRefresh方法实际是交给了

子类DispatcherServlet实现,DispatcherServlet的onRefresh方法源码如下:

/** DispatcherServlet onRefresh方法 */
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }
    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        /** 初始化处理器映射器HandlerMapping */
        initHandlerMappings(context);
        /** 初始化处理器适配器handlerAdapter */
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        /** 初始化视图解析器ViewResolver */
        initViewResolvers(context);
        initFlashMapManager(context);
    }

可以看出onRefresh方法主要是初始化相关组件,如初始化业务处理器映射器HandlerMapping、处理器适配器HandlerAdapter、视图解析器ViewResolver等,这里着重分析HandlerMapping和HandlerAdapter的初始化。

5.1.1、处理器映射器初始化

首先看处理器映射器的初始化,方法为DispatcherServlet的initHandlerMapping(ApplicationContext context), 源码如下:

 1 /** 初始化处理器映射器 */
 2     private void initHandlerMappings(ApplicationContext context) {
 3         this.handlerMappings = null;
 4         /** 1.先尝试从Spring容器中获取所有HandlerMapping s*/
 5         if (this.detectAllHandlerMappings) {
 6             MapString, HandlerMapping matchingBeans =
 7                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
 8             if (!matchingBeans.isEmpty()) {
 9                 this.handlerMappings = new ArrayList(matchingBeans.values());
10                 AnnotationAwareOrderComparator.sort(this.handlerMappings);
11             }
12         }
13         else {
14             try {
15                 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
16                 this.handlerMappings = Collections.singletonList(hm);
17             }
18             catch (NoSuchBeanDefinitionException ex) {
19             }
20         }
21 
22         /** 2.如果Spring容器中没有HandlerMapping,那么就初始化默认的HandlerMapping*/
23         if (this.handlerMappings == null) {
24             // 初始化默认HandlerMapping
25             this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
26         }
27     }
28 
29     /** 获取默认策略 */
30     protected T ListT getDefaultStrategies(ApplicationContext context, ClassT strategyInterface) {
31         String key = strategyInterface.getName();
32         /** 1.从配置文件中获取默认策略
33          *  配置文件为DispatcherServlet.properties
34          *  key为策略类全路径
35          * */
36         String value = defaultStrategies.getProperty(key);
37         if (value != null) {
38             String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
39             ListT strategies = new ArrayList(classNames.length);
40             for (String className : classNames) {
41                 try {
42                     /** 2.反射初始化所有策略实例*/
43                     Class clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
44                     Object strategy = createDefaultStrategy(context, clazz);
45                     strategies.add((T) strategy);
46                 }
47                 catch (ClassNotFoundException ex) {
48                 }
49                 catch (LinkageError err) {
50                 }
51             }
52             return strategies;
53         }
54         else {
55             return new LinkedList();
56         }
57     }

首先尝试从Spring容器中获取所有HandlerMapping的bean,如果不存在就加载默认处理器映射器,getDefaultStrategies方法是从配置文件DispatcherServlet.properties中加载默认配置,配置文件内容如下:

 1 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
 2 
 3 org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
 4 
 5 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
 6     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
 7     org.springframework.web.servlet.function.support.RouterFunctionMapping
 8 
 9 org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
10     org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
11     org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
12     org.springframework.web.servlet.function.support.HandlerFunctionAdapter
13 
14 
15 org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
16     org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
17     org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
18 
19 org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
20 
21 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
22 
23 org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

可以发现默认HandlerMapping为BeanNameUrlHandlerMapping、RequestMappingHandlerMapping和RouterFunctionMapping,以RequestMappingHandlerMapping为例,实现了InitializingBean,

所以初始化后会执行afterPropertiesSet方法,该方法初始化属性,并调用父类AbstractHandlerMapping的afterPropertiesSet方法,该方法又执行了方法initHandlerMethods方法,AbstractHandlerMapping的

initHandlerMethods方法实质就是初始化方法映射的方法,逻辑如下:

/** 初始化路径和方法映射 */
    protected void initHandlerMethods() {
        /** 1.遍历Spring容器中所有的bean */
        for (String beanName : getCandidateBeanNames()) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                /** 2.处理所有后续的bean */
                processCandidateBean(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }
    protected void processCandidateBean(String beanName) {
        Class beanType = null;
        try {
            /** 1.获取bean的Class对象 */
            beanType = obtainApplicationContext().getType(beanName);
        }
        catch (Throwable ex) {
        }
        /** 2.调用isHandler方法判断该bean是否是业务处理器*/
        if (beanType != null  isHandler(beanType)) {
            /** 2.寻找业务处理器中映射方法 */
            detectHandlerMethods(beanName);
        }
    }
    /** 判断bean是否是业务处理器( 被Controller或RequestMapping注解修饰 )*/
    protected boolean isHandler(Class beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

遍历Spring容器中所有的bean,判断bean中是否包含@Controller或@RequestMapping注解,如果包含那么就是业务处理器,那么就执行detectHandlerMethods方法处理,该方法逻辑如下:

protected void detectHandlerMethods(Object handler) {
        /** 1.获取处理器Class对象 */
        Class handlerType = (handler instanceof String 
                obtainApplicationContext().getType((String) handler) : handler.getClass());
        if (handlerType != null) {
            Class userType = ClassUtils.getUserClass(handlerType);
            /** 2.寻找所有映射方法集合,存入MapMethod,RequestMappingInfo中
             *  RequestMappingInfo就是方法映射关系类 */
            MapMethod, T methods = MethodIntrospector.selectMethods(userType,
                    (MethodIntrospector.MetadataLookupT) method - {
                        try {
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    });
            methods.forEach((method, mapping) - {
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                /** 注册处理器、方法、映射关系, 缓存在MappingRegistry实例的Map中 */
                registerHandlerMethod(handler, invocableMethod, mapping);
            });
        }
    }

先从业务处理器中寻找所有映射方法封装成映射关系实例,然后将处理器、方法和映射关系实例注册到MappingRegistry实例中。

5.1.2、处理器适配器初始化

处理器适配器HandlerAdapter的初始化过程和处理器映射器HandlerMapping的初始化过程如出一辙,最终落实到默认的适配器RequestMappingHandlerAdapter的初始化,最终是重写了afterPropertiesSet方法。

5.2、SpringMVC工作流程

Servlet工作流程实际就是接收到客户端请求之后执行service方法,所以SpringMVC的请求处理入口就是DispatcherServlet的service方法,DispatcherServlet的service方法是执行了父类FrameworkServlet的service方法。

该方法又执行了FrameworkServlet的processRequest方法,最终调用了子类的doService方法,DispatcherServlet的doService方法就是处理业务逻辑的核心方法,源码如下:

/** DispatcherServlet 处理业务方法 */
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        /** 1.请求参数快照,将请求参数缓存起来 */
        MapString, Object attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }
        /** 2.请求参数添加配置 */
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
        if (this.flashMapManager != null) {
            FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
            if (inputFlashMap != null) {
                request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
            }
            request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
            request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
        }
        try {
            /** 3.执行分配请求处理 */
            doDispatch(request, response);
        }
        finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                if (attributesSnapshot != null) {
                    restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }

首先进行参数处理,然后调用doDispatch方法分配请求,逻辑如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                /** 1.根据请求从HandlerMapping中查询具体的业务处理器 */
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
                /** 2.根据业务处理器查询对应业务处理器适配器 */
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified)  isGet) {
                        return;
                    }
                }
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                /** 3.调用处理器适配器的handle方法处理具体的业务逻辑 */
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                applyDefaultViewName(processedRequest, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                //...
            }
            /** 4.处理请求执行结果 */
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        } catch (Exception ex) {
            //...
        } finally {
            //...
        }
    }

核心逻辑比较清晰,先从处理器映射器中查询请求对应的业务处理器,然后再根据业务处理器找到处理器适配器,然后调用适配器的handle方法处理业务,最终执行processDispatchResult方法处理请求的处理结果。

getHandler逻辑就是从集合handlerMappings中找到匹配的处理器;

getHandlerAdapter就是从集合handlerAdapters中找到对应的适配器;

handle方法就是通过反射机制执行对应处理器的方法;

processDispatchResult就是将执行结果封装成ModelAndView对象;

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/124355.html

(0)

相关推荐

  • css选择器的作用是什么

    技术css选择器的作用是什么这篇文章主要介绍“css选择器的作用是什么”,在日常操作中,相信很多人在css选择器的作用是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”css选择器的作用

    攻略 2021年11月10日
  • 如何理解Mysql Replication

    技术如何理解Mysql Replication如何理解Mysql Replication,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Mys

    攻略 2021年11月20日
  • 信息安全工程师-软考中级-备考笔记:第十一章 网络物理隔离技术原理与应用

    技术信息安全工程师-软考中级-备考笔记:第十一章 网络物理隔离技术原理与应用 信息安全工程师-软考中级-备考笔记:第十一章 网络物理隔离技术原理与应用第11章 网络物理隔离技术原理与应用
    网络物理隔离概

    礼包 2021年11月14日
  • Oracle索引范围扫描操作流程是什么

    技术Oracle索引范围扫描操作流程是什么本篇内容主要讲解“Oracle索引范围扫描操作流程是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Oracle索引范围扫描操作流

    攻略 2021年11月4日
  • IE6有哪些常见CSS解析Bug

    技术IE6有哪些常见CSS解析Bug这篇文章主要讲解了“IE6有哪些常见CSS解析Bug”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“IE6有哪些常见CSS解析Bug”吧

    攻略 2021年12月10日
  • linux系统查看任务计划程序(linux查看系统中的计划任务命令)

    技术linux系统中计划任务怎么实现这篇文章主要讲解了“linux系统中计划任务怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“linux系统中计划任务怎么实现”吧

    攻略 2021年12月23日