Spring之WebMvcConfigurationSupport

    注: WebMvcConfigurationSupport是spring5.x的配置方式。如果是6.x,则是通过实现WebMvcConfigurer的方式实现(建议再加上@EnableWebMvc)

     WebMvcConfigurationSupport是mvc的核心配置。开发spring,了解和掌握这个是必须的。

     为了简约篇幅,本文把"WebMvcConfigurationSupport"缩写为wms。

     本文主要关注围绕DispatcherServlet(分发者服务程序)发生的和wms有关的一些内容,不关注http请求在容器部分的机制和代码。

     通过本文能够:

  1. 了解wms是做什么的
  2. 了解大体如何使用wms
  3. 作为了解和使用wms的一个简单参考

一、wms的介绍

1.原文注释

    This is the main class providing the configuration behind the MVC Java config.
    It is typically imported by adding @EnableWebMvc to anapplication @Configuration class.
    An alternative more advanced option is to extend directly from this class and override methods as necessary,
    remembering to add @Configuration to the subclass and @Bean to overridden @Bean methods.
    For more details see the javadoc of @EnableWebMvc.

This class registers the following HandlerMappings:
    •RequestMappingHandlerMapping ordered at 0 for mapping requests to annotated controller methods.
    •HandlerMapping ordered at 1 to map URL paths directly to view names.
    •BeanNameUrlHandlerMapping ordered at 2 to map URL paths to controller bean names.
    •RouterFunctionMapping  ordered at 3 to map router functions.
    •HandlerMapping ordered at Integer.MAX_VALUE-1 to serve static resource requests.
    •HandlerMapping ordered at Integer.MAX_VALUE to forward requests to the default servlet.

Registers these HandlerAdapters:
    •RequestMappingHandlerAdapter for processing requests with annotated controller methods.
    •HttpRequestHandlerAdapter for processing requests with HttpRequestHandlers.
    •SimpleControllerHandlerAdapter for processing requests with interface-based Controllers.
    •HandlerFunctionAdapter for processing requests with router functions.

Registers a HandlerExceptionResolverComposite with this chain ofexception resolvers:
    •ExceptionHandlerExceptionResolver for handling exceptions through org.springframework.web.bind.annotation.ExceptionHandler methods.
    •ResponseStatusExceptionResolver for exceptions annotated with org.springframework.web.bind.annotation.ResponseStatus.
    •DefaultHandlerExceptionResolver for resolving known Springexception types

Registers an AntPathMatcher and a UrlPathHelperto be used by:
    •the RequestMappingHandlerMapping,
    •the HandlerMapping for ViewControllers
    •and the HandlerMapping for serving resources
    Note that those beans can be configured with a PathMatchConfigurer.

Both the RequestMappingHandlerAdapter and the ExceptionHandlerExceptionResolver are configured with default instances of the following by default:
    •a ContentNegotiationManager
    •a Default FormattingConversionService
    •an org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean if a JSR-303 implementation is available on the classpath
    •a range of HttpMessageConverters depending on the third-partylibraries available on the classpath.

  我们翻译下:

    wms是webMvc通过java代码方式配置的主类。
    典型地,可以通过给一个应用的配置类(带@Configuration)添加@EnableWebMvc注解,即可导入Mvc java 配置。
    另外一个更加高级的替代选项是继承本类,并根据需要重写一些方法,并记得为这个子类添加@Configuration注解,同时为那些重写@Bean方法添加@Bean注解。
    更多的内容,请参考@EnableWebMvc的java文档

    本类注册以下处理器映射:
    .RequestMappingHandlerMapping(RequestMapping处理器映射) ,顺序为0,用于映射带注解的控制器方法
    .HandlerMapping (处理器映射),顺序1,用于映射url路径和视图名称
    .BeanNameUrlHandlerMapping(bean名称处理器映射),顺序2,用于映射url路径到控制器bean名称
    .RouterFunctionMapping(路由器功能映射),顺序3,用于映射路由函数
    .HandlerMapping (处理器映射),顺序Integer.MAX_VALUE-1,用于处理静态资源请求
    .HandlerMapping (处理器映射),顺序Integer.MAX_VALUE,用于服务器内部重定向到一个默认的servlet


    注册这些处理器适配器:
    •RequestMappingHandlerAdapter(RequestMapping处理器适配器),用于处理到带注解的控制器方法请求
    •HttpRequestHandlerAdapter(http请求处理器适配器),用于处理 带HttpRequestHanders的请求
    •SimpleControllerHandlerAdapter(简单控制器处理器适配器),用于处理基于接口的控制的请求
    •HandlerFunctionAdapter(处理器功能适配器),用于处理带路由器功能的请求


    注册处理器异常解析复合器,该复合器带有一些异常处理器:    
    •ExceptionHandlerExceptionResolver(异常处理器异常解析器),用于处理org.springframework.web.bind.annotation.ExceptionHandler的异常
    •ResponseStatusExceptionResolver(响应状态异常解析器),用于处理org.springframework.web.bind.annotation.ResponseStatus异常
    •DefaultHandlerExceptionResolver(默认处理器异常解析器),用于处理已知的的spring异常类


    注册一个antPathMatcher和一个urlPathHelper,以便能够被以下对象使用:
    •RequestMappingHandlerMapping(RequestMapping处理器映射)
    •HandlerMapping for ViewControllers ,用于视图控制器的处理器映射
    •HandlerMapping for serving resources ,用于处理资源的处理器映射
    注意,以上这些bean可以通过PathMatchCOnfigurer配置。


    RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver都由以下对象的默认实例配置了:
    .ContentNegotiationManager(媒体类型管理器,用于侦测请求的媒体类型)
    .FormattingConversionService(格式转换服务)
    .org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean(bean验证器,如果类路径具有JSR-303的实现)
    .HttpMessageConverters(http消息转换器)。具体有几个转换器,需要看类路径的三方实现库的多寡

  

2.功能

     如它的名称,即执行各种webMvc的配置,通过在其中定义大量的有关Bean(大约有25个左右),方便MVC的流程的特定环节从Bean工厂中获取这些bean,并利用这些Bean完成webMvc的大部分工作。

     概括下,wms就是这些功能:

  • 注册处理器映射,以便把请求导向具体的控制器、控制器方法、视图、资源。注意,这些映射器的目的是做一个关系匹配
  • 注册处理器适配器,为具体的功能选择具体的处理程序。例如参数解析,消息转换等
  • 注册异常处理器
  • 注册路径映射解析有关类

      总而言之,言而总之,wms就是告诉spring用于处理请求的有关工具,这些工具用于处理映射关系,解析参数,返回消息等等

      一个完整的web请求和响应过程中需要执行的动作所使用的配置(程序、配置)基本都可以在wms中进行管理,记住这一点基本上算是对wms有所了解了

二、名词解析

需要记住和理解的名词非常多,只能挑本人关注的。

1.解释器/解决器

英文:Resolver

中文含义:问题解决者。  针对不同的场景,可以有很多的解释。在本文中,按照习惯,我们从用途进行翻译,大体翻译为解释器,转换器都可以。

2.拦截器

英文:interceptor

中文含义:进行拦截的人/物。在spring中,专门指拦截http请求的一段程序。和过滤器基本一样,没有什么本质上的区别。不过拦截器可以打断请求的过程,而过滤器主要做重定向(如果有必要)

3.控制器、参数、方法

      控制器:controller,对应注解@Controller

      参数:parameter,这里主要阐述的是控制器中方法的入参

      方法:method,这里指控制器中的方法(有Request的方法)

      我们日常spring编程主要针对这三者。

      某种程度上,只要会复制粘贴+mvc你就可以说自己是一个java开发工程师了,是不是很容易啊?

4.返回值、消息

     返回值:return value。控制器方法大部分情况下都有返回值,如果没有,那么spring也会给一个默认的响应

     消息:message.这里指从客户端发送的请求消息或者是服务端返回给客户端的消息。这里我们主要关心ResponseBody注解。

5.Cors

     英文:CORS(Cross-origin resource sharing)

     中文:跨源资源共享

     一般情况下,web服务器不允许跨源资源共享,但很多时候又有这个需求。所以需要指定什么资源可以被什么其它非同源请求访问。

6.资源和视图

     资源:resource,spring通常指静态的数据(包括图片,脚本,文本,多媒体信息等等)

     视图:view,spring指展示信息的页面

7.验证器

     英文:validator,spring通常指用于校验特定参数的简单业务逻辑

8.格式化器和转换器

     格式化器:formatter

     转换器:converter

     二者有相通之处,但基本一致,格式和转换基本即使你中有我,我中有你,密不可分。其作用,顾名思义,就是进行转化/格式化。 例如消息转换、属性转换等。

9.异常

   具体略。

10.应用上下文和sevlet上下文

   这两个太重要,因为WebMvcConfigurationSupport实现的很大一部分和应用上下文、服务器上下文有关。

  • ApplicationContext:应用上下文,属于spring自有的一个应用上下文,主要管理spring的bean。能够管理bean,绝对是spring的最核心能力之一。

        包路径:org.springframework.context.ApplicationContext

  • ServletContext:服务器上下文,准确地说,通常地说,它指的是web服务器/容器的根上下文,容器通常为每个应用创建一个服务器上下文,保存应用和web相关的许多基本信息。

        包路径:javax.servlet.ServletContext

   我们开发的系统,某个方便面来说就是和两个东西关联:web+bean。web和bean有关的上下文就是 ServletContext,ApplicationContext。

11.媒体/媒介类型

    英文:MediaType

    包路径:org.springframework.http.MediaType

    根据介绍,媒体/媒介类型实为MimeType的子类,spring仅仅对它做了一些包装,方便使用。

    所以,根本上要理解MiME在http协议中的地位。

    Mime的非常友好的介绍见这里:MIME 类型 - HTTP | MDN (mozilla.org)

    或者看这里 MIME(多用途互联网邮件扩展类型)_百度百科 (baidu.com)

    两个结合起来,就能够明白mime是什么东西。

    如果有什么值得记的,就是为什么叫” mail extensions"(邮件扩展)。

    邮件大概是互联网最早传递的数据信息,而且基本上是最重要的,所以开始命名的时候就这么叫了。但是现在iana(互联网号码分配机构)又慢慢要抛弃mime这个概念,改为mediaType(媒体类型)

    很明显这么称呼是更加合理的,如果没有什么特别说明,“媒体类型”就是表示MINE或者上下文类型(context-type)

 12.请求映射处理器映射器(RequestMappingHandlerMapping)

    注意这个前缀 RequestMapping(请求映射)本身是注解的名称(@RequestMapping)。

    所以这个东西可以理解为RequestMapping注解的处理器映射器,大体作用是在注解和资源之间建立映射关系。

    我们看下源码(默认的):

@Bean
    @SuppressWarnings("deprecation")
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

        RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
        mapping.setOrder(0);
        mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
        mapping.setContentNegotiationManager(contentNegotiationManager);
        mapping.setCorsConfigurations(getCorsConfigurations());

        PathMatchConfigurer pathConfig = getPathMatchConfigurer();
        if (pathConfig.getPatternParser() != null) {
            mapping.setPatternParser(pathConfig.getPatternParser());
        }
        else {
            mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
            mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());

            Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
            if (useSuffixPatternMatch != null) {
                mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
            }
            Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
            if (useRegisteredSuffixPatternMatch != null) {
                mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
            }
        }
        Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
        if (useTrailingSlashMatch != null) {
            mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
        }
        if (pathConfig.getPathPrefixes() != null) {
            mapping.setPathPrefixes(pathConfig.getPathPrefixes());
        }

        return mapping;
    }

 

   这个代码核心是创建一个RequestMapping的处理器映射器,这个映射器又包含了什么东西了?

  1. 添加默认的转换器和资源url管理器的拦截器
  2. 添加请求媒体类型管理器
  3. 添加了跨域请求配置
  4. 添加了路径匹配器,以及路径有关的一些其它程序

13.请求映射处理器适配器(RequestMappingHandlerAdapter)

     RequestMapping注解处理器适配器。

     看源码(默认):

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
    adapter.setContentNegotiationManager(contentNegotiationManager);
    adapter.setMessageConverters(getMessageConverters());
    adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
    adapter.setCustomArgumentResolvers(getArgumentResolvers());
    adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

    if (jackson2Present) {
        adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
        adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
    }

    AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();
    if (configurer.getTaskExecutor() != null) {
        adapter.setTaskExecutor(configurer.getTaskExecutor());
    }
    if (configurer.getTimeout() != null) {
        adapter.setAsyncRequestTimeout(configurer.getTimeout());
    }
    adapter.setCallableInterceptors(configurer.getCallableInterceptors());
    adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

    return adapter;
}
  1. 设置媒体类型管理器(和映射器一样,都必须了解请求的媒体类型)
  2. 设置消息转换器
  3. web绑定初始化器(和转换服务、验证器有关)
  4. 设置自定义参数解释器
  5. 设置自定义返回值处理器
  6. 添加jackson请求体RequestBody顾问(如果有jackson类)
  7. 添加jackson响应体ResponseBody顾问(如果有jackson类)
  8. 配置异步任务执行器,设置异步请求超时。如果有配置异步
  9. 配置异步的可调用拦截器
  10. 配置异步延时结果拦截器

       把这个内容和RequestMappingHanlderMapping的内容对照下,我们就更能够理解二者的区别。

       --------------------------------------------------------------------------------------------------------------------

  • 映射器:主管资源和路径有关的内容
  • 适配器:主管具体请求消息处理返回消息

       注:spring已经提供了消息处理器的默认实现JackSon.

        RequestMappingHandlerAdapter和RequestMappingHandleMapping是DispatcherServlet(分发器)的主要处理内容。

        以下是分发器属性的主要内容:

      

/** MultipartResolver used by this servlet. */
    @Nullable
    private MultipartResolver multipartResolver;

    /** LocaleResolver used by this servlet. */
    @Nullable
    private LocaleResolver localeResolver;

    /** ThemeResolver used by this servlet. */
    @Nullable
    private ThemeResolver themeResolver;

    /** List of HandlerMappings used by this servlet. */
    @Nullable
    private List<HandlerMapping> handlerMappings;

    /** List of HandlerAdapters used by this servlet. */
    @Nullable
    private List<HandlerAdapter> handlerAdapters;

    /** List of HandlerExceptionResolvers used by this servlet. */
    @Nullable
    private List<HandlerExceptionResolver> handlerExceptionResolvers;

    /** RequestToViewNameTranslator used by this servlet. */
    @Nullable
    private RequestToViewNameTranslator viewNameTranslator;

    /** FlashMapManager used by this servlet. */
    @Nullable
    private FlashMapManager flashMapManager;

    /** List of ViewResolvers used by this servlet. */
    @Nullable
    private List<ViewResolver> viewResolvers;

 

三、spring-mvc种http请求大概执行过程

    这么多名词,其实本质上就是围绕http展开的,具体来说就是围绕spring的http实现来展开。

    我们使用spring的主要目的就是为了web(http)应用。可以说,没有web,spring的存在的意义基本上就没有了。

    利用ide提供的调试工具,最容易能够直观地了解一个http请求的大概执行过程。如果愿意,还可以详细到每一行代码。

    下图是调试的时候,显示的调用链:

   


四、常用-配置拦截器

     如何配置拦截器,这个没有什么太多可说。

     记住一点,现在不但spring自身实现功能的时候使用了很多的拦截器(这个在springCloud中很明显),就是一般的开发人员也喜欢()用大量的拦截器。

     我们只能感激一点:现在电脑越来越快了。

     配置例子。

@Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // 以下是启用 token认证的. 本例使用cookie认证的时候,请注释掉,避免无法完成测试
        // 反过来,如果启用了token认证,那么过滤器验证就可以取消掉 ,或者取消 上文的 registrationBean()
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("*.js")
                .excludePathPatterns("*.html").excludePathPatterns("*.css").excludePathPatterns("/login")
                .excludePathPatterns("/logout").excludePathPatterns("/index").excludePathPatterns("/");
        super.addInterceptors(registry);
    }

 

五、常用-方法参数(输入)解析(请求)

    spring已经有提供默认的以下几个注解的处理:@RequstBody,@RequestParam

    但是当我们开发api的时候,常常有这样的需求:

  • 在过滤器或者拦截器拦截请求并获取有关参数
  • 在具体的控制方法中想获取请求的一些固定信息,例如登录用户信息,授权信息等等 。

     5.1 例子-自定义参数注解

、 如果每个地方都写,有点麻烦,所以spring允许自定义的参数解析。

    例子:

a.定义一个注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface SessionAtrrAnnotation {

}
b.继承并实现HandlerMethodArgumentResolver
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(SessionAtrrAnnotation.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { return webRequest.getNativeRequest(HttpServletRequest.class).getSession().getAttribute("userInfo"); } }
c.在wms中注册 @Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new LoginUserArgumentResolver()); } d.应用 @RequestMapping(value = "/deleteById") @ResponseBody public PublicReturn deleteById(@SessionAtrrAnnotation LoginUserInfo loginInfo) { //TODO:删除用户 return null; }

 

    5.2 自定义特定数据类型解析

    这种自定义类型,有两种情况:

    a.解析非JSON媒体类型的参数

    b.解析媒体类型为JSON的参数中某个属性

    这个网络上有很多解决方案,例如:

    SpringMVC自定义处理多种日期格式的格式转换器_二木成林的博客-CSDN博客_springmvc日期转换   -- 这个是解析非json媒体类型参数的

    不过作者是比较传统的xml配置,如果是springboot,直接在wms中覆盖addFormatters即可。

    fastjson序列化时间自定义格式_biangabiang的博客-CSDN博客_fastjson自定义序列化格式 --使用阿里巴巴的fastjson,不过记得先配置Http消息转换器为FastJson(覆盖wms中的configureMessageConverters)

     这是因为fastjson允许针对不同类型使用不同的序列化程序。

   5.3媒体类型为JSON,且使用JackSon处理特定类型

    无论是JackSon还是FastJson的,它们都是实现了HttpMessageConverter接口。 标准一样,细节有所区别而已。

    所以,如果使用默认的JackSon的时候,可以和网上常常提到的FASTjson一样的思路来解决问题。

    有关内容可以看这个:Jackson Tutorial | Baeldung

    然而比较简单的方式还是覆盖下configureMessageConverters,在其中定制化MappingJackson2HttpMessageConverter的各种属性。

    例如网上有这样的例子:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder().serializers(LOCAL_DATETIME_SERIALIZER)
      .serializationInclusion(JsonInclude.Include.NON_NULL);
    return new MappingJackson2HttpMessageConverter(builder.build());
}

 

   如果仅仅是想自定义序列化或者反序列化器,那么使用注解即可:

@JsonSerialize(using = FamilyJSONSerializer.class)
public class Family {
    private Integer id;
    private String name;
    private Date addTime;
    private Date lastOptime;
    private String batchNo;
}

 FamilyJSONSerializer的代码如下:

package study.config.message;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import study.model.family.Family;

public class FamilyJSONSerializer  extends JsonSerializer<Family>{

    @Override
    public void serialize(Family value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value==null) {
            gen.writeString("{}");
            return;
        }
        gen.writeString(value.toString());
    }

    @Override
    public Class<Family> handledType(){
        return Family.class;
    }
}

 

     自定义消息的解析,通常不是那么迫切,只要知道大概即可。

     没有必要耗费太多的时间研究,并重新做一个轮子。

 

六、常用-响应消息(http消息转换)配置(响应)

     spring的设计是允许有多个http消息转换器,每个转换器对应不同的媒体类型。这些转换器只要实现HttpMessageConverter接口即可。

     当然如果你自己自定义,也可以让一个转换器对应n种媒体类型,或者n个转换器对应一个媒体类型。

     如果是这种情况,spring会采用一定的选择缺略,保证每个媒体类型都可以进行适当的转换。

     网上太多了,不再详细说明了。常见的即使用fastJson--覆盖wms中的configureMessageConverters。

     下面是jackson的例子:

@Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(new StringHttpMessageConverter());
        converters.add(new ResourceHttpMessageConverter());
        converters.add(new ResourceRegionHttpMessageConverter());
        MappingJackson2HttpMessageConverter jconverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper=jconverter.getObjectMapper();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString("");
            }
        });
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(dateFormat);
        converters.add(jconverter);
    }

   主要两点:设置日期格式、null输出为"",节约前端编码工作量。

七、常用-配置视图和资源解释

    例如:

   @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/")
                .addResourceLocations("classpath:/public/")
                .addResourceLocations("classpath:/resources/")
                .addResourceLocations("file:" + uploadPath);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("main/index");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
    }

 

八、小结

     对于大部分的javaEE开发的工程师而言,都有必要理解webMvc的机制,以及wms的配置。

     wms既简单又复杂,涉及到webMvc的方法面面,相关的源码非常之多,如要透彻了解其原理和机制只有一个方法:仔细阅读并做好笔记。

     此外,建议在阅读本代码前,先掌握http请求的基本原理和流程。另外为了提高阅读和理解的效率,建议开启调试模式,逐步调试,就能够较快了解这里所涉及的有关知识。

     我个人一直喜欢用这个方法。现在ide对于这个的支持非常好,无论是eclipse,idea还是netbean,似乎除了跟踪不到机器指令,任何东西都可以跟踪和窥探,强大到难以置信。

     在调试过程中,可以发现代码是从web容器(或者服务器)开始执行的,并最好从org.springframework.web.servlet.DispatcherServlet开始,因为在此类之前的大部分属于容器的api。

 

posted @ 2022-05-05 15:00  正在战斗中  阅读(3286)  评论(2编辑  收藏  举报