SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

刚接触SpringMVC,对它的xml文件配置一直比较模模糊糊,最近花了一点时间稍微看了下源代码,再加上调试,开始逐渐理解它,网上的类似的内容有很多,写本文主要是自己加深一下理解。本文适合用过SpringMVC的开发者,言归正传,首先搭建一个最简单的工程体验一下。 

该工程是基于maven的,pom配置不再说明,所使用的spring版本4.0.5。 
首先是web.xml文件配置,最简单的配置 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<!DOCTYPE web-app PUBLIC

 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

 "http://java.sun.com/dtd/web-app_2_3.dtd" >

 

<web-app>

  <display-name>Archetype Created Web Application</display-name>

  <servlet>

        <servlet-name>mvc</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

 

    <servlet-mapping>

        <servlet-name>mvc</servlet-name>

        <url-pattern>/*</url-pattern>

    </servlet-mapping>

</web-app>

然后是mvc-servlet.xml文件的配置,上面配置DispatcherServlet会默认加载[servlet-name]-servlet.xml文件。对于我的配置,会去加载mvc-servlet.xml文件。 
mvc-servlet.xml文件的内容: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

    http://www.springframework.org/schema/mvc

    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd

    http://www.springframework.org/schema/util

    http://www.springframework.org/schema/util/spring-util-2.0.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.2.xsd">

 

    <bean name="/index" class="com.lg.mvc.HomeAction"></bean>

    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">

        <property name="templateLoaderPath" value="/WEB-INF/views" />

        <property name="defaultEncoding" value="utf-8" />

        <property name="freemarkerSettings">

            <props>

                <prop key="locale">zh_CN</prop>

            </props>

        </property>

    </bean>

    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">

        <property name="suffix" value=".html" />

        <property name="contentType" value="text/html;charset=utf-8" />

        <property name="requestContextAttribute" value="request" />

        <property name="exposeRequestAttributes" value="true" />

        <property name="exposeSessionAttributes" value="true" />

    </bean>

</beans>

在该配置中定义了一个HomeAction的Bean。内容为: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package com.lg.mvc;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.mvc.Controller;

 

public class HomeAction implements Controller{

 

    @Override

    public ModelAndView handleRequest(HttpServletRequest request,

            HttpServletResponse response) throws Exception {

        return new ModelAndView("hello");

    }

}

这是最原始的mvc做法,要继承Controller接口,先从原始的说起,最后再过渡到@Controller和@RequestMapping注解式的配置。它在mvc-serlet.xml文件中的配置有一个关键的属性name="/index"。 
WEB-INF/view目录下有一个简单的hello.html,内容为: 

?


1

2

3

4

5

6

7

8

<html>

    <head>

     

    </head>

    <body>

        hello lg !

    </body>

</html>

至此该工程就写完了,部署到tomcat中,项目路径为/,运行一下。 
访问 http://localhost:8080/index 
 
至此整个工程就算搭建成功了。 

下面就要说说原理了。 
用过python Django框架的都知道Django对于访问方式的配置就是,一个url路径和一个函数配对,你访问这个url,就会直接调用这个函数,简单明了。对于java的面向对象来说,就要分两步走。第一步首先要找到是哪个对象,即handler,本工程的handler则是HomeAction对象。第二步要找到访问的函数,即HomeAction的handleRequest方法。所以就出现了两个源码接口 HandlerMapping和HandlerAdapter,前者负责第一步,后者负责第二步。借用网上的SpringMVC架构图。 
 
HandlerMapping接口的实现(只举了我认识的几个) : 

  • BeanNameUrlHandlerMapping :通过对比url和bean的name找到对应的对象 
    SimpleUrlHandlerMapping :也是直接配置url和对应bean,比BeanNameUrlHandlerMapping功能更多 
    DefaultAnnotationHandlerMapping : 主要是针对注解配置@RequestMapping的,已过时 
    RequestMappingHandlerMapping :取代了上面一个 

HandlerAdapter 接口实现: 

  • HttpRequestHandlerAdapter : 要求handler实现HttpRequestHandler接口,该接口的方法为                                                             void handleRequest(HttpServletRequest request, HttpServletResponse response)也就是  handler必须有一个handleRequest方法 

    SimpleControllerHandlerAdapter:要求handler实现Controller接口,该接口的方法为ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response),也就是本工程采用的 

    AnnotationMethodHandlerAdapter :和上面的DefaultAnnotationHandlerMapping配对使用的,也已过时 

    RequestMappingHandlerAdapter : 和上面的RequestMappingHandlerMapping配对使用,针对@RequestMapping 

先简单的说下这个工程的流程,访问http://localhost:8080/index首先由DispatcherServlet进行转发,通过BeanNameUrlHandlerMapping(含有 /index->HomeAction的配置),找到了HomeAction,然后再拿HomeAction和每个adapter进行适配,由于HomeAction实现了Controller接口,所以最终会有SimpleControllerHandlerAdapter来完成对HomeAction的handleRequest方法的调度。然后就顺利的执行了我们想要的方法,后面的内容不在本节中说明。 

了解了大概流程,然后就需要看源代码了。 
首先就是SpringMVC的入口类,DispatcherServlet,它实现了Servlet接口,不再详细说DispatcherServlet的细节,不然又是一大堆的内容。每次请求都会调用它的doService->doDispatch,我们关注的重点就在doDispatch方法中。 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

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

                      //这个是重点,第一步由HandlerMapping找到对应的handler

                // Determine handler for the current request.

                mappedHandler = getHandler(processedRequest);

                if (mappedHandler == null || mappedHandler.getHandler() == null) {

                    noHandlerFound(processedRequest, response);

                    return;

                }

 

                // Determine handler adapter for the current request.

                       //这是第二步,找到合适的HandlerAdapter,然后由它来调度执行handler的方法

                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

 

                // Process last-modified header, if supported by the handler.

                String method = request.getMethod();

                boolean isGet = "GET".equals(method);

                if (isGet || "HEAD".equals(method)) {

                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

                    if (logger.isDebugEnabled()) {

                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);

                    }

                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

                        return;

                    }

                }

 

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {

                    return;

                }

 

                try {

                    // Actually invoke the handler.

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                }

                finally {

                    if (asyncManager.isConcurrentHandlingStarted()) {

                        return;

                    }

                }

 

                applyDefaultViewName(request, mv);

                mappedHandler.applyPostHandle(processedRequest, response, mv);

            }

            catch (Exception ex) {

                dispatchException = ex;

            }

            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

        }

        catch (Exception ex) {

            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);

        }

        catch (Error err) {

            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);

        }

        finally {

            if (asyncManager.isConcurrentHandlingStarted()) {

                // Instead of postHandle and afterCompletion

                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

                return;

            }

            // Clean up any resources used by a multipart request.

            if (multipartRequestParsed) {

                cleanupMultipart(processedRequest);

            }

        }

    }

第一步详细查看: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

        for (HandlerMapping hm : this.handlerMappings) {

            if (logger.isTraceEnabled()) {

                logger.trace(

                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");

            }

            HandlerExecutionChain handler = hm.getHandler(request);

            if (handler != null) {

                return handler;

            }

        }

        return null;

    }

可以看到就是通过遍历所有已注册的HandlerMapping来找到对应的handler,然后构建出一个HandlerExecutionChain,它包含了handler和HandlerMapping本身的一些拦截器,如下 

?


1

2

3

4

5

6

7

8

9

10

public class HandlerExecutionChain {

 

    private final Object handler;

 

    private HandlerInterceptor[] interceptors;

 

    private List<HandlerInterceptor> interceptorList;

         

        //其他代码省略

}

其中HandlerMapping的getHandler实现: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

        Object handler = getHandlerInternal(request);

        if (handler == null) {

            handler = getDefaultHandler();

        }

        if (handler == null) {

            return null;

        }

        // Bean name or resolved handler?

        if (handler instanceof String) {

            String handlerName = (String) handler;

            handler = getApplicationContext().getBean(handlerName);

        }

        return getHandlerExecutionChain(handler, request);

    }

这里的getHandlerInternal(request)是个抽象方法,由具体的HandlerMapping来实现,获取到的handler如果为空,则获取默认配置的handler,如果handler为String类型,则表示这个则会去Spring容器里面去找这样名字的bean。 
再看下BeanNameUrlHandlerMapping的getHandlerInternal(request)的具体实现(通过一系列的接口设计,之后再好好看看这个设计,到BeanNameUrlHandlerMapping这只用实现该方法中的一部分),如下 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {

 

    /**

     * Checks name and aliases of the given bean for URLs, starting with "/".

     */

    @Override

    protected String[] determineUrlsForHandler(String beanName) {

        List<String> urls = new ArrayList<String>();

        if (beanName.startsWith("/")) {

            urls.add(beanName);

        }

        String[] aliases = getApplicationContext().getAliases(beanName);

        for (String alias : aliases) {

            if (alias.startsWith("/")) {

                urls.add(alias);

            }

        }

        return StringUtils.toStringArray(urls);

    }

 

}

这里面注释说,bean的name必须以/开头,它才处理,将信息存储在Map<String, Object> handlerMap中,对于本工程来说就是{'/index':HomeAction对象}。 
至此这里完成了第一步,下面开始第二步,即方法HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());的具体实现: 

?


1

2

3

4

5

6

7

8

9

10

11

12

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

        for (HandlerAdapter ha : this.handlerAdapters) {

            if (logger.isTraceEnabled()) {

                logger.trace("Testing handler adapter [" + ha + "]");

            }

            if (ha.supports(handler)) {

                return ha;

            }

        }

        throw new ServletException("No adapter for handler [" + handler +

                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");

    }

遍历所有的HandlerAdapter,判断他们是否支持这个handler。 
我们来看下HttpRequestHandlerAdapter的supports(handler)方法: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

public class HttpRequestHandlerAdapter implements HandlerAdapter {

 

    @Override

    public boolean supports(Object handler) {

          //就是判断handler是否实现了HttpRequestHandler接口

        return (handler instanceof HttpRequestHandler);

    }

 

    @Override

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

            throws Exception {

           //若handler实现了HttpRequestHandler接口,则调用该接口的方法,执行我们在该方法中写的业务逻辑

        ((HttpRequestHandler) handler).handleRequest(request, response);

        return null;

    }

 

    @Override

    public long getLastModified(HttpServletRequest request, Object handler) {

        if (handler instanceof LastModified) {

            return ((LastModified) handler).getLastModified(request);

        }

        return -1L;

    }

 

}

同理SimpleControllerHandlerAdapter也是这样类似的逻辑 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

 

    @Override

    public boolean supports(Object handler) {

        return (handler instanceof Controller);

    }

 

    @Override

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

            throws Exception {

 

        return ((Controller) handler).handleRequest(request, response);

    }

 

    @Override

    public long getLastModified(HttpServletRequest request, Object handler) {

        if (handler instanceof LastModified) {

            return ((LastModified) handler).getLastModified(request);

        }

        return -1L;

    }

 

}

剩余两个AnnotationMethodHandlerAdapter和RequestMappingHandlerAdapter就比较复杂,我也没看。 
按照本工程的配置,则SimpleControllerHandlerAdapter是支持HomeAction的,然后就会执行SimpleControllerHandlerAdapter的handle(processedRequest, response, mappedHandler.getHandler())方法。本质上就会调用HomeAction实现Controller接口的方法。至此就分析完了。 
了解过程了之后,然后就是最重要的也是经常配置出问题的地方。DispatcherServlet的handlerMappings和handlerAdapters的来源问题。 

DispatcherServlet初始化的时候,会调用一个方法如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

protected void initStrategies(ApplicationContext context) {

        initMultipartResolver(context);

        initLocaleResolver(context);

        initThemeResolver(context);

//初始化一些HandlerMapping

        initHandlerMappings(context);

//初始化一些HandlerAdapter

        initHandlerAdapters(context);

        initHandlerExceptionResolvers(context);

        initRequestToViewNameTranslator(context);

        initViewResolvers(context);

        initFlashMapManager(context);

    }

这里可以看到,它会初始化一些HandlerMapping和HandlerAdapter,这两个方法非常重要,理解了这两个方法你就会知道,配置不对问题出在哪里,下面具体看下这两个方法: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

private void initHandlerMappings(ApplicationContext context) {

        this.handlerMappings = null;

 

        if (this.detectAllHandlerMappings) {

            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.

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

            }

        }

    }

detectAllHandlerMappings是DispatcherServlet的一个属性,你是可以在web.xml中配置的,默认是true,如果为true,则会去从本工程mvc-servlet.xml文件中去探测所有实现了HandlerMapping的bean,如果有,则加入DispatcherServlet的handlerMappings中。如果detectAllHandlerMappings为false,则直接去容器中找id="handlerMapping"且实现了HandlerMapping的bean.如果以上都没找到,则会去加载默认的HandlerMapping。 

?


1

2

/** Detect all HandlerMappings or just expect "handlerMapping" bean? */

    private boolean detectAllHandlerMappings = true;

本工程由于没有配置HandlerMapping,所以它会去加载默认的,下面看看默认的配置是什么 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {

        String key = strategyInterface.getName();

//defaultStrategies存储了默认的配置

        String value = defaultStrategies.getProperty(key);

        if (value != null) {

            String[] classNames = StringUtils.commaDelimitedListToStringArray(value);

            List<T> strategies = new ArrayList<T>(classNames.length);

            for (String className : classNames) {

                try {

                    Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());

                    Object strategy = createDefaultStrategy(context, clazz);

                    strategies.add((T) strategy);

                }

                catch (ClassNotFoundException ex) {

                    throw new BeanInitializationException(

                            "Could not find DispatcherServlet's default strategy class [" + className +

                                    "] for interface [" + key + "]", ex);

                }

                catch (LinkageError err) {

                    throw new BeanInitializationException(

                            "Error loading DispatcherServlet's default strategy class [" + className +

                                    "] for interface [" + key + "]: problem with class file or dependent class", err);

                }

            }

            return strategies;

        }

        else {

            return new LinkedList<T>();

        }

    }

继续看看defaultStrategies是如何初始化的: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

private static final Properties defaultStrategies;

 

    static {

        // Load default strategy implementations from properties file.

        // This is currently strictly internal and not meant to be customized

        // by application developers.

        try {

//这里的DEFAULT_STRATEGIES_PATH就是DispatcherServlet.properties

            ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);

            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);

        }

        catch (IOException ex) {

            throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());

        }

    }

这里使用静态代码块来加载配置文件DispatcherServlet.properties,它所在位置就是和DispatcherServlet同一目录下面的,如下图所示: 

 
该默认的配置文件的内容如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

# Default implementation classes for DispatcherServlet's strategy interfaces.

# Used as fallback when no matching beans are found in the DispatcherServlet context.

# Not meant to be customized by application developers.

 

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

 

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

 

#这里就是默认的HandlerMapping的配置

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\

    org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

#这里就是默认的HandlerAdapter的配置

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\

    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\

    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

 

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\

    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\

    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

 

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

 

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

 

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

也就是说,当你什么都没有配置时,默认会加载以上的配置。正是由于有了上述默认配置的BeanNameUrlHandlerMapping(它要求name必须是以/开头的),它才会存储我们在mvc-servlet.xml中配置的<bean name="/index" class="com.lg.mvc.HomeAction"></bean>,同样正是由于有了SimpleControllerHandlerAdapter(由于handler实现了Controller接口,所以它的support方法支持我们的handler),才会调度执行HomeAction的handleRequest方法。

时间: 2024-10-07 20:05:45

SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门的相关文章

SpringMVC源码解读之HandlerMapping - AbstractUrlHandlerMapping系列request分发_java

AbstractHandlerMapping实现HandlerMapping接口定的getHandler 1. 提供getHandlerInternal模板方法给子类实现      2. 如果没有获取Handler,则使用默认的defaultHandler 3. 如果handler是string类型,从context获取实例 4. 通过getHandlerExecutionChain封装handler,添加interceptor // AbstractHandlerMapping /** * L

SpringMVC源码解读之 HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化_java

 AbstractDetectingUrlHandlerMapping是通过扫描方式注册Handler,收到请求时由AbstractUrlHandlerMapping的getHandlerInternal进行分发. 共有5个子类,一个抽象类. 与SimpleUrlHandlerMapping类似,通过覆写initApplicationContext,然后调用detectHandlers进行初始化. detectHandlers通过BeanFactoryUtils扫描应用下的Object,然后预留

SpringMVC源码解析- HandlerAdapter - ModelFactory(转)

ModelFactory主要是两个职责: 1. 初始化model 2. 处理器执行后将modle中相应参数设置到SessionAttributes中   我们来看看具体的处理逻辑(直接充当分析目录): 1. 初始化model 1.1 解析类上使用的sessionAttributres,将获取参数合并到mavContainer中 1.2 执行注解了@ModelAttribute的方法,并将结果同步到Model 参数名的生成规则:@ModelAttribute中定义的value > 方法的返回类型决

SpringMVC源码解读之HandlerMapping_java

概述 对于Web开发者,MVC模型是大家再熟悉不过的了,SpringMVC中,满足条件的请求进入到负责请求分发的DispatcherServlet,DispatcherServlet根据请求url到控制器的映射(HandlerMapping中保存),HandlerMapping最终返回HandlerExecutionChain,其中包含了具体的处理对象handler(也即我们编程时写的controller)以及一系列的拦截器interceptors,此时DispatcherServlet会根据返

SpringMVC源码解析 - HandlerMethod

HandlerMethod及子类主要用于封装方法调用相关信息,子类还提供调用,参数准备和返回值处理的职责. 分析下各个类的职责吧(顺便做分析目录): HandlerMethod 封装方法定义相关的信息,如类,方法,参数等. 使用场景:HandlerMapping时会使用 InvocableHandlerMethod 添加参数准备,方法调用功能 使用场景:执行使用@ModelAttribute注解会使用 ServletInvocableHandlerMethod 添加返回值处理职责,Respons

SpringMVC源码总结(五)Tomcat的URIEncoding、useBodyEncodingForURI和CharacterEncodingFilter

继续上一章节的乱码问题.上一篇文章仅仅说了设置Tomcat的URIEncoding可以解决乱码问题,这篇文章便会讲述这一背后的内容.首先说明下,光看是没用的,要多实验实验.  目前我的tomcat版本为:7.0.55,spring所有文章的版本始终为4.0.5  本文章会从tomcat的源码角度来解析Tomcat的两个参数设置URIEncoding和useBodyEncodingForURI.  对于一个请求,常用的有两种编码方式,如下:  ? 1 2 3 4 5 6 7 8 9 10 11 1

SpringMVC源码总结(八)类型转换PropertyEditor的背后

PropertyEditor是Spring最初采用的转换策略.将会转移到Converter上.本文章主要对@InitBinder注解背后代码层面的运行过程做介绍.所以最好先熟悉它的用法然后来看通代码流程.  先看实例,controller代码如下:  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Controller public class FormAction{       // 这样的方法里,一般是用来注册一些Pro

SpringMVC源码总结(十)自定义HandlerMethodArgumentResolver

上一篇文章介绍了HandlerMethodArgumentResolver的来龙去脉,这篇就要说说自定义HandlerMethodArgumentResolver来解决我们的需求,本文提供了四种解决方案.  需求,有一个Teacher类和Student类,他们都有属性name和age:  前端form表单为:  ? 1 2 3 4 5 6 7 <form action="/test/two" method="post" >             <

springMvc源码学习之:spring源码总结

转载自:http://www.cnblogs.com/davidwang456/p/4213652.html   spring beans下面有如下源文件包: org.springframework.beans, 包含了操作java bean的接口和类.org.springframework.beans.annotation, 支持包,提供对java 5注解处理bean样式的支持.org.springframework.beans.factory, 实现spring轻量级IoC容器的核心包.or