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{

     

// 这样的方法里,一般是用来注册一些PropertyEditor

    @InitBinder 

    public void initBinder(WebDataBinder binder) throws Exception { 

        DateFormat df = new SimpleDateFormat("yyyy---MM---dd HH:mm:ss"); 

        CustomDateEditor dateEditor = new CustomDateEditor(df, true); 

        binder.registerCustomEditor(Date.class, dateEditor);     

    }  

     

     

    @RequestMapping(value="/test/json",method=RequestMethod.GET)

    @ResponseBody

    public Map<String,Object> getFormData(Date date){

        Map<String,Object> map=new HashMap<String,Object>();

        map.put("name","lg");

        map.put("age",23);

        map.put("date",new Date());

        return map;

    }

}

xml文件仅仅开启mvc:ananotation-driven: 

?


1

<mvc:annotation-driven />

然后访问  http://localhost:8080/test/json?date=2014---08---3 03:34:23,便看到成功的获取到了数据。接下来源代码代码分析这一过程: 

由于使用了@RequestMapping所以会选择RequestMappingHandlerAdapter来调度执行相应的方法,如下: 

?


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

/**

     * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}

     * if view resolution is required.

     */

    private ModelAndView invokeHandleMethod(HttpServletRequest request,

            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

 

        ServletWebRequest webRequest = new ServletWebRequest(request, response);

//我们关注的重点重点重点重点重点重点重点重点

        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

        ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

 

        ModelAndViewContainer mavContainer = new ModelAndViewContainer();

        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

        modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);

        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

 

        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);

        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

 

        final 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 + "]");

            }

            requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);

        }

 

        requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

 

        if (asyncManager.isConcurrentHandlingStarted()) {

            return null;

        }

 

        return getModelAndView(mavContainer, modelFactory, webRequest);

    }

这里面就是整个执行过程。首先绑定请求参数到方法的参数上,然后执行方法,接下来根据方法返回的类型来选择合适的HandlerMethodReturnValueHandler来进行处理,最后要么走view路线,要么直接写入response的body中返回。 

我们此时关注的重点是:如何绑定请求参数到方法的参数上的呢? 
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); 
针对每次对该handlerMethod请求产生一个绑定工厂,由这个工厂来完成数据的绑定。 
这里的handlerMethod包含了 controller对象FormAction和、test/json映射到的方法即getFormData。 
然后详细看下getDataBinderFactory的实现: 

?


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

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {

//这里的handlerType便是controller的类型FormAction

        Class<?> handlerType = handlerMethod.getBeanType();

        Set<Method> methods = this.initBinderCache.get(handlerType);

        if (methods == null) {

//关注点1:找出FormAction类的所有的含有@InitBinder的方法(方法的返回类型必须为void),找到后同时缓存起来

            methods = HandlerMethodSelector.selectMethods(handlerType, INIT_BINDER_METHODS);

            this.initBinderCache.put(handlerType, methods);

        }

        List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();

        // Global methods first

//关注点2:再寻找出全局的初始化Binder的方法

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

                }

            }

        }

        for (Method method : methods) {

            Object bean = handlerMethod.getBean();

            initBinderMethods.add(createInitBinderMethod(bean, method));

        }

//关注点3:找到了所有的与该handlerMethod有关的初始化binder的方法,保存起来

        return createDataBinderFactory(initBinderMethods);

    }

上面稍微做了些注释,然后看下详细的内容: 
关注点1:就是使用过滤,过滤类为:INIT_BINDER_METHODS,如下 

?


1

2

3

4

5

6

7

8

9

10

/**

     * MethodFilter that matches {@link InitBinder @InitBinder} methods.

     */

    public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() {

 

        @Override

        public boolean matches(Method method) {

            return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;

        }

    };

这个过滤类就是在handlerType即FormAction中过滤那些含有@InitBinder注解的方法。找到了之后就缓存起来,供下次使用。key为:handlerType,value为找到的方法。存至initBinderCache中。 

关注点2:从initBinderAdviceCache中获取所有支持这个handlerType的method。这一块有待继续研究,这个initBinderAdviceCache是如何初始化来的等等。针对目前的工程来说,initBinderAdviceCache是为空的。 

关注点3:遍历所有找到的和handlerType有关的method,然后封装成InvocableHandlerMethod,如下: 

?


1

2

3

4

for (Method method : methods) {

            Object bean = handlerMethod.getBean();

            initBinderMethods.add(createInitBinderMethod(bean, method));

        }

?


1

2

3

4

5

6

7

private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {

        InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);

        binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);

        binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));

        binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        return binderMethod;

    }

在封装的过程中,同时设置一些RequestMappingHandlerAdapter的一些参数进去initBinderArgumentResolvers、webBindingInitializer、parameterNameDiscoverer。 
封装完所有的方法后,创建出最终的WebDataBinderFactory。如下: 

?


1

2

3

4

5

protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)

            throws Exception {

 

        return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());

    }

getWebBindingInitializer()也是RequestMappingHandlerAdapter的webBindingInitializer参数。 

至此绑定数据的工厂完成了,包含了这个handlerType的所有的PropertyEditor。这是准备工作,然后就是等待执行这个我们自己的方法getFormData执行时来完成参数的绑定过程。 

绑定参数过程即getFormData的执行过程如下: 

?


1

2

3

ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

其中的requestMappingMethod经过了进一步的包装,已经包含刚才已经创建的绑定工厂。 
执行过程如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,

            Object... providedArgs) throws Exception {

 

        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

        if (logger.isTraceEnabled()) {

            StringBuilder sb = new StringBuilder("Invoking [");

            sb.append(getBeanType().getSimpleName()).append(".");

            sb.append(getMethod().getName()).append("] method with arguments ");

            sb.append(Arrays.asList(args));

            logger.trace(sb.toString());

        }

        Object returnValue = invoke(args);

        if (logger.isTraceEnabled()) {

            logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");

        }

        return returnValue;

    }

分两大步,绑定参数和执行方法体。最重要的就是如何来绑定参数呢? 

?


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

private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,

            Object... providedArgs) throws Exception {

 

        MethodParameter[] parameters = getMethodParameters();

        Object[] args = new Object[parameters.length];

        for (int i = 0; i < parameters.length; i++) {

            MethodParameter parameter = parameters[i];

            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);

            GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());

            args[i] = resolveProvidedArgument(parameter, providedArgs);

            if (args[i] != null) {

                continue;

            }

            if (this.argumentResolvers.supportsParameter(parameter)) {

                try {

                    args[i] = this.argumentResolvers.resolveArgument(

                            parameter, mavContainer, request, this.dataBinderFactory);

                    continue;

                }

                catch (Exception ex) {

                    if (logger.isTraceEnabled()) {

                        logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);

                    }

                    throw ex;

                }

            }

            if (args[i] == null) {

                String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);

                throw new IllegalStateException(msg);

            }

        }

        return args;

    }

绑定参数又引出来另一个重要名词:HandlerMethodArgumentResolver。args[i] = this.argumentResolvers.resolveArgument( 
parameter, mavContainer, request, this.dataBinderFactory);的具体内容如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

/**

     * Iterate over registered {@link HandlerMethodArgumentResolver}s and invoke the one that supports it.

     * @exception IllegalStateException if no suitable {@link HandlerMethodArgumentResolver} is found.

     */

    @Override

    public Object resolveArgument(

            MethodParameter parameter, ModelAndViewContainer mavContainer,

            NativeWebRequest webRequest, WebDataBinderFactory binderFactory)

            throws Exception {

 

        HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);

        Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");

        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);

    }

遍历所有已注册的HandlerMethodArgumentResolver,然后找出一个适合的来进行参数绑定,对于本工程来说,getFormData(Date date)的参数date默认是request params级别的,所以使用RequestParamMethodArgumentResolver来处理这一过程。处理过程如下: 

?


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

@Override

    public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,

            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

 

        Class<?> paramType = parameter.getParameterType();

        NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);

 

        Object arg = resolveName(namedValueInfo.name, parameter, webRequest);

        if (arg == null) {

            if (namedValueInfo.defaultValue != null) {

                arg = resolveDefaultValue(namedValueInfo.defaultValue);

            }

            else if (namedValueInfo.required) {

                handleMissingValue(namedValueInfo.name, parameter);

            }

            arg = handleNullValue(namedValueInfo.name, arg, paramType);

        }

        else if ("".equals(arg) && (namedValueInfo.defaultValue != null)) {

            arg = resolveDefaultValue(namedValueInfo.defaultValue);

        }

 

        if (binderFactory != null) {

            WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);

            arg = binder.convertIfNecessary(arg, paramType, parameter);

        }

 

        handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

 

        return arg;

    }

NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);获取参数信息,就是按照@RequestParam的3个属性来收集的,即defaultValue=null、required=false、name=date, 
Object arg = resolveName(namedValueInfo.name, parameter, webRequest);然后就是获取原始数据,获取过程如下: 

?


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

@Override

    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {

        Object arg;

 

        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);

        MultipartHttpServletRequest multipartRequest =

            WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);

 

        if (MultipartFile.class.equals(parameter.getParameterType())) {

            assertIsMultipartRequest(servletRequest);

            Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");

            arg = multipartRequest.getFile(name);

        }

        else if (isMultipartFileCollection(parameter)) {

            assertIsMultipartRequest(servletRequest);

            Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");

            arg = multipartRequest.getFiles(name);

        }

        else if(isMultipartFileArray(parameter)) {

            assertIsMultipartRequest(servletRequest);

            Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");

            arg = multipartRequest.getFiles(name).toArray(new MultipartFile[0]);

        }

        else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {

            assertIsMultipartRequest(servletRequest);

            arg = servletRequest.getPart(name);

        }

        else if (isPartCollection(parameter)) {

            assertIsMultipartRequest(servletRequest);

            arg = new ArrayList<Object>(servletRequest.getParts());

        }

        else if (isPartArray(parameter)) {

            assertIsMultipartRequest(servletRequest);

            arg = RequestPartResolver.resolvePart(servletRequest);

        }

        else {

            arg = null;

            if (multipartRequest != null) {

                List<MultipartFile> files = multipartRequest.getFiles(name);

                if (!files.isEmpty()) {

                    arg = (files.size() == 1 ? files.get(0) : files);

                }

            }

            if (arg == null) {

//对于本工程,我们的重点在这里这里这里这里这里这里

                String[] paramValues = webRequest.getParameterValues(name);

                if (paramValues != null) {

                    arg = paramValues.length == 1 ? paramValues[0] : paramValues;

                }

            }

        }

 

        return arg;

    }

通过webRequest.getParameterValues(name)来获取原始的字符串。这里便有涉及到了容器如tomcat的处理过程,这一获取参数的过程在本系列的第五篇文章tomcat的获取参数中进行了详细的源码介绍,那一篇主要是介绍乱码的。本文章不再介绍,接着说,这样就可以获取到我们请求的原始字符串"2014---08---3 03:34:23",接下来便是执行转换绑定的过程: 

?


1

2

3

4

if (binderFactory != null) {

            WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);

            arg = binder.convertIfNecessary(arg, paramType, parameter);

        }

这一过程就是要寻找我们已经注册的所有的PropertyEditor来进行转换,如果还没有找到,则使用另一套转换流程,使用conversionService来进行转换。我们慢慢来看这一过程,有了binderFactory便可以创建出WebDataBinder,具体的创建过程如下: 

?


1

2

3

4

5

6

7

8

9

public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)

            throws Exception {

        WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);

        if (this.initializer != null) {

            this.initializer.initBinder(dataBinder, webRequest);

        }

        initBinder(dataBinder, webRequest);

        return dataBinder;

    }

先创建出WebDataBinder,然后使用initializer的initBinder方法来初始化一些PropertyEditor,initializer的类型为我们常见的ConfigurableWebBindingInitializer即在mvc:annotation-driven时默认注册的最终设置为RequestMappingHandlerAdapter的webBindingInitializer属性值。this.initializer.initBinder(dataBinder, webRequest);过程如下: 

?


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

@Override

    public void initBinder(WebDataBinder binder, WebRequest request) {

        binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);

        if (this.directFieldAccess) {

            binder.initDirectFieldAccess();

        }

        if (this.messageCodesResolver != null) {

            binder.setMessageCodesResolver(this.messageCodesResolver);

        }

        if (this.bindingErrorProcessor != null) {

            binder.setBindingErrorProcessor(this.bindingErrorProcessor);

        }

        if (this.validator != null && binder.getTarget() != null &&

                this.validator.supports(binder.getTarget().getClass())) {

            binder.setValidator(this.validator);

        }

        if (this.conversionService != null) {

            binder.setConversionService(this.conversionService);

        }

        if (this.propertyEditorRegistrars != null) {

            for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {

                propertyEditorRegistrar.registerCustomEditors(binder);

            }

        }

    }

即设置一些我们conversionService、messageCodesResolver、validator 等,这些参数即我们在mvc:annotation中进行设置的,若无设置,采用默认的。 
继续执行initBinder(dataBinder, webRequest); 

?


1

2

3

4

5

6

7

8

9

10

public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {

        for (InvocableHandlerMethod binderMethod : this.binderMethods) {

            if (isBinderMethodApplicable(binderMethod, binder)) {

                Object returnValue = binderMethod.invokeForRequest(request, null, binder);

                if (returnValue != null) {

                    throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);

                }

            }

        }

    }

执行那些适合我们已经创建的WebDataBinder,怎样才叫适合的呢?看isBinderMethodApplicable(binderMethod, binder)方法 

?


1

2

3

4

5

protected boolean isBinderMethodApplicable(HandlerMethod initBinderMethod, WebDataBinder binder) {

        InitBinder annot = initBinderMethod.getMethodAnnotation(InitBinder.class);

        Collection<String> names = Arrays.asList(annot.value());

        return (names.size() == 0 || names.contains(binder.getObjectName()));

    }

当initBinderMethod上的@InitBinder注解指定了value,该value可以是多个,当它包含了我们的方法的参数date,则这个initBinderMethod就会被执行。当@InitBinder注解没有指定value,则也会被执行。所以为了不用执行一些不必要的initBinderMethod,我们最好为这些initBinderMethod上的@InitBinder加上value限定。对于我们写的initBinder便因此开始执行了。 
由binderFactory创建出来的WebDataBinder就此完成,然后才是详细的转换过程: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,

            Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {

 

        Object convertedValue = newValue;

 

        // Custom editor for this type?

        PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);

 

        ConversionFailedException firstAttemptEx = null;

 

        // No custom editor but custom ConversionService specified?

        ConversionService conversionService = this.propertyEditorRegistry.getConversionService();

 

            //略

}

这里首先使用已注册的PropertyEditor,当仍然没有找到时才使用ConversionService。对于本工程来说,由于已经手动注册了对于Date的转换的PropertyEditor即CustomDateEditor,然后便会执行CustomDateEditor的具体的转换过程。至此,大体过程就算是完了。

时间: 2024-10-21 15:33:39

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

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

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

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_java

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

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

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

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

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

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 <!DOCT

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

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源码解析 - HandlerMethod

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