发布时间:2025-06-24 19:33:10 作者:北方职教升学中心 阅读量:235
web容器初始化类(代替web.xml)
/** * web工程的初始化类,用来代替web.xml * 以下配置的都是以前在web.xml中配置的 */publicclassWebAppInitializerextendsAbstractAnnotationConfigDispatcherServletInitializer{/** * Spring的配置,目前不涉及Spring,这里设置为空 */@OverrideprotectedClass<?>[]getRootConfigClasses(){returnnewClass<?>[0];}/** * SpringMVC的配置 */@OverrideprotectedClass<?>[]getServletConfigClasses(){returnnewClass<?>[]{SpringMVCConfig.class};}/** * 用于配置DispatcherServlet的映射路径 */@OverrideprotectedString[]getServletMappings(){returnnewString[]{"/"};}/** * 注册过滤器 */@OverrideprotectedFilter[]getServletFilters(){// 字符编码过滤器CharacterEncodingFiltercharacterEncodingFilter =newCharacterEncodingFilter();characterEncodingFilter.setEncoding("UTF-8");characterEncodingFilter.setForceEncoding(true);// HiddenHttpMethodFilter 用于支持 PUT、创建DispatcherServlet对象1.3、// WebMvcConfigurationSupport类方法protectedfinalvoidaddDefaultHttpMessageConverters(List<HttpMessageConverter<?>>messageConverters){// 默认消息转换器messageConverters.add(newByteArrayHttpMessageConverter());messageConverters.add(newStringHttpMessageConverter());messageConverters.add(newResourceHttpMessageConverter());messageConverters.add(newResourceRegionHttpMessageConverter());...// jacksonif(jackson2Present){Jackson2ObjectMapperBuilderbuilder =Jackson2ObjectMapperBuilder.json();if(this.applicationContext !=null){builder.applicationContext(this.applicationContext);}messageConverters.add(newMappingJackson2HttpMessageConverter(builder.build()));}// Google Gson 库中的一个核心类,Java对象与JSON 格式字符串进行相互转换elseif(gsonPresent){messageConverters.add(newGsonHttpMessageConverter());}// JDK 类库JSON类elseif(jsonbPresent){messageConverters.add(newJsonbHttpMessageConverter());}...}
3.3.2、实例化
- 3.3.1.1、RequestMappingInfo、ResponseBodyAdvice)
- 3.3.2.2、HandlerMethodArgumentResolver方法参数解析器
publicinterfaceHandlerMethodArgumentResolver{/** * 此解析器是否支持给定的方法参数 */booleansupportsParameter(MethodParameterparameter);/** * 将方法参数解析为给定请求的参数值 */@NullableObjectresolveArgument(MethodParameterparameter,@NullableModelAndViewContainermavContainer,NativeWebRequestwebRequest,@NullableWebDataBinderFactorybinderFactory)throwsException;}
- 方法参数解析器有很多,差不多一个注解就对应一个参数解析器

3.3.2.3、// WebMvcConfigurerComposite类classWebMvcConfigurerCompositeimplementsWebMvcConfigurer{privatefinalList<WebMvcConfigurer>delegates =newArrayList<>();@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){for(WebMvcConfigurerdelegate :this.delegates){delegate.addInterceptors(registry);}}@OverridepublicvoidaddCorsMappings(CorsRegistryregistry){for(WebMvcConfigurerdelegate :this.delegates){delegate.addCorsMappings(registry);}}@OverridepublicvoidconfigureViewResolvers(ViewResolverRegistryregistry){for(WebMvcConfigurerdelegate :this.delegates){delegate.configureViewResolvers(registry);}}@OverridepublicvoidconfigureMessageConverters(List<HttpMessageConverter<?>>converters){for(WebMvcConfigurerdelegate :this.delegates){delegate.configureMessageConverters(converters);}}}
3、HandlerExceptionResolver异常处理器- 一句话解释它:Hander异常抛错后调用的方法
与消息转换器很像,先遍历所有WebMvcConfigurer实现类configureHandlerExceptionResolvers中新增
的异常处理器,如果没有开发者或者第三方新增,那么添加默认的的异常处理器,再调用扩展方法,也就是遍历所有WebMvcConfigurer实现类,调用他们的extendHandlerExceptionResolvers方法,对异常处理器做最后修改
。之前文章Spring源码解析(四):单例bean的创建流程有介绍过,bean对象创建后会调用各种初始化方法,其实就包括调用InitializingBean接口
的afterPropertiesSet
方法来实现初始化
。获取所有跨域配置
3.2.2、
- RequestMappingHandlerAdapter实现了afterPropertiesSet方法如下
// RequestMappingHandlerAdapter类方法@OverridepublicvoidafterPropertiesSet(){// 初始化@ControllerAdviceinitControllerAdviceCache();// 设置默认的方法参数解析器if(this.argumentResolvers ==null){List<HandlerMethodArgumentResolver>resolvers =getDefaultArgumentResolvers();this.argumentResolvers =newHandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if(this.initBinderArgumentResolvers ==null){List<HandlerMethodArgumentResolver>resolvers =getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers =newHandlerMethodArgumentResolverComposite().addResolvers(resolvers);}// 设置默认的返回值处理器if(this.returnValueHandlers ==null){List<HandlerMethodReturnValueHandler>handlers =getDefaultReturnValueHandlers();this.returnValueHandlers =newHandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}
3.3.2.1、如果开发者和第三方都没有添加,那么设置默认的消息转换器,设置完以后,再调用扩展方法
,也就是遍历所有WebMvcConfigurer实现类,调用他们的extendMessageConverters
方法,对消息转换器做最后修改
。SpringServletContainerInitializer
- 1、WebMvcConfigurer接口
在讲DelegatingWebMvcConfiguration之前先说下WebMvcConfigurer接口,因为下面内容都是围绕着WebMvcConfigurer接口展开的。加载自定义异常处理器// ExceptionHandlerExceptionResolver类方法@OverridepublicvoidafterPropertiesSet(){// 初始化异常处理增强类initExceptionHandlerAdviceCache();if(this.argumentResolvers ==null){List<HandlerMethodArgumentResolver>resolvers =getDefaultArgumentResolvers();this.argumentResolvers =newHandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if(this.returnValueHandlers ==null){List<HandlerMethodReturnValueHandler>handlers =getDefaultReturnValueHandlers();this.returnValueHandlers =newHandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}
- 筛选异常处理器类:
@ControllerAdvice
类且方法上存在@ExceptionHandler
// ExceptionHandlerExceptionResolver类方法privatevoidinitExceptionHandlerAdviceCache(){if(getApplicationContext()==null){return;}// 获取所有@ControllerAdvice注解的bean,创建成ControllerAdviceBean,添加到集合中List<ControllerAdviceBean>adviceBeans =ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());for(ControllerAdviceBeanadviceBean :adviceBeans){Class<?>beanType =adviceBean.getBeanType();if(beanType ==null){thrownewIllegalStateException("Unresolvable type for ControllerAdviceBean: "+adviceBean);}// 筛选方法上@ExceptionHandler注解ExceptionHandlerMethodResolverresolver =newExceptionHandlerMethodResolver(beanType);if(resolver.hasExceptionMappings()){this.exceptionHandlerAdviceCache.put(adviceBean,resolver);}if(ResponseBodyAdvice.class.isAssignableFrom(beanType)){this.responseBodyAdvice.add(adviceBean);}}}// ExceptionHandlerMethodResolver类属性和方法publicstaticfinalMethodFilterEXCEPTION_HANDLER_METHODS=method ->AnnotatedElementUtils.hasAnnotation(method,ExceptionHandler.class);publicExceptionHandlerMethodResolver(Class<?>handlerType){for(Methodmethod :MethodIntrospector.selectMethods(handlerType,EXCEPTION_HANDLER_METHODS)){for(Class<?extendsThrowable>exceptionType :detectExceptionMappings(method)){addExceptionMapping(exceptionType,method);}}}
至此,SpringMVC启动重要的组件都介绍完毕。

1、SimpleUrlHandlerMapping
适配器HandlerAdapter
publicinterfaceHandlerAdapter{/** * 因为有多个HandlerMapping和HandlerAdapter * 对于HandlerAdapter是否支持对应的HandlerMapping,通过此方法判断 */booleansupports(Objecthandler);/** * 具体调用Hangder的方法 */@NullableModelAndViewhandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException;}
- 上一步中不同映射器通过请求映射到的
Handler
是不确定类型
的- @RequestMapping注解方式获取到的是具体的Method
- 其他实现接口方式获取到的是具体的Class
- 此时拿到Handler去执行具体的方法时候,方式是
不统一
的 - 那么适配器就出现了
RequestMappingHandlerAdapter
就是处理@RequestMapping注解的Handler
3.2、StandardWrapper中有介绍。web容器初始化入口
2、跨域配置等 @OverrideprotectedvoidconfigureDefaultServletHandling(DefaultServletHandlerConfigurerconfigurer){this.configurers.configureDefaultServletHandling(configurer);}@OverrideprotectedvoidaddInterceptors(InterceptorRegistryregistry){this.configurers.addInterceptors(registry);}@OverrideprotectedvoidaddCorsMappings(CorsRegistryregistry){this.configurers.addCorsMappings(registry);}@OverrideprotectedvoidconfigureViewResolvers(ViewResolverRegistryregistry){this.configurers.configureViewResolvers(registry);}@OverrideprotectedvoidconfigureMessageConverters(List<HttpMessageConverter<?>>converters){this.configurers.configureMessageConverters(converters);}@OverrideprotectedvoidconfigureHandlerExceptionResolvers(List<HandlerExceptionResolver>exceptionResolvers){this.configurers.configureHandlerExceptionResolvers(exceptionResolvers);}...}
调用DelegatingWebMvcConfiguration重写的MVC配置方法实际就是 RequestMappingHandlerMapping的复杂类图看一下(有删减) @RequestMapping注解肯定是在容器启动时候解析的,那么这个工作就放在RequestMappingHandlerMapping这个bean对象的初始化阶段来完成。获取候选bean DispatcherServlet类图如下: Tomcat启动容器加载Servelt(这里是DispatcherServlet)并初始化,就会调用到这里。一般我们会导入对应的配置添加到对应的注册器
中。HandlerMethodReturnValueHandler返回值处理器3.2.1、通过实现WebMvcConfigurer接口,可以
定制化SpringMVC的配置
,例如添加拦截器、方法参数解析器、获取消息转换器Jackson
,那么这里会添加MappingJackson2HttpMessageConverter
消息转换器。注册过滤器
// WebMvcConfigurationSupport类方法@BeanpublicHandlerExceptionResolverhandlerExceptionResolver(@Qualifier("mvcContentNegotiationManager")ContentNegotiationManagercontentNegotiationManager){// 创建空集合List<HandlerExceptionResolver>exceptionResolvers =newArrayList<>();// 这里就是调用DelegatingWebMvcConfiguration重写的方法// 其实就是寻找WebMvcConfigurer实现类是否添加异常处理器configureHandlerExceptionResolvers(exceptionResolvers);if(exceptionResolvers.isEmpty()){addDefaultHandlerExceptionResolvers(exceptionResolvers,contentNegotiationManager);}// 这里就是调用DelegatingWebMvcConfiguration重写的方法,扩展异常处理器extendHandlerExceptionResolvers(exceptionResolvers);HandlerExceptionResolverCompositecomposite =newHandlerExceptionResolverComposite();composite.setOrder(0);composite.setExceptionResolvers(exceptionResolvers);returncomposite;}
- ExceptionHandlerExceptionResolver:这个异常处理器内
包含
所有的自定义异常处理器- 因为这个对象不是bean对象,这里手动调用初始化接口的方法afterPropertiesSet
- 最后添加默认异常处理器DefaultHandlerExceptionResolver
protectedfinalvoidaddDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver>exceptionResolvers,ContentNegotiationManagermvcContentNegotiationManager){// 这个异常处理器内包含所有的自定义异常处理器ExceptionHandlerExceptionResolverexceptionHandlerResolver =createExceptionHandlerExceptionResolver();exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);exceptionHandlerResolver.setMessageConverters(getMessageConverters());exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());if(jackson2Present){exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(newJsonViewResponseBodyAdvice()));}if(this.applicationContext !=null){exceptionHandlerResolver.setApplicationContext(this.applicationContext);}// 手动调用初始化接口的初始化方法exceptionHandlerResolver.afterPropertiesSet();exceptionResolvers.add(exceptionHandlerResolver);// ResponseStatus异常处理器ResponseStatusExceptionResolverresponseStatusResolver =newResponseStatusExceptionResolver();responseStatusResolver.setMessageSource(this.applicationContext);exceptionResolvers.add(responseStatusResolver);// 默认异常处理器exceptionResolvers.add(newDefaultHandlerExceptionResolver());}
3.4.1、SpringServletContainerInitializer的作用解析
@EnableWebMvc
1、// WebMvcConfigurationSupportprotectedfinalMap<String,CorsConfiguration>getCorsConfigurations(){if(this.corsConfigurations ==null){CorsRegistryregistry =newCorsRegistry();addCorsMappings(registry);this.corsConfigurations =registry.getCorsConfigurations();}returnthis.corsConfigurations;}
3.2.2、过滤器等
// WebMvcConfigurationSupportprotectedfinalMap<String,CorsConfiguration>getCorsConfigurations(){if(this.corsConfigurations ==null){CorsRegistryregistry =newCorsRegistry();addCorsMappings(registry);this.corsConfigurations =registry.getCorsConfigurations();}returnthis.corsConfigurations;}
总结SpringServletContainerInitializer
作用:加载自定义的WebApplicationInitializer初始化核心接口
的实现类WebAppInitializer,调用onStartup
方法来实现web容器初始化。
接下来的入口就在 启动tomcat发送请求结果 DelegatingWebMvcConfiguration的类图如下:自定义g配置类SpringMVCConfi
这里,因为它的配置类注解@Configuration
(也是@Component),@ComponentScan(扫描@Controller注解)
和@EnableWebMvc(导入DelegatingWebMvcConfiguration.class)
注解都会被扫描解析到。测试Controller// 接受User对象修改并返回@PostMapping("/test")@ResponseBodypublicUsertest(@RequestBodyUseruser){// 修改名字为李四然后返回给前台user.setName("李四");System.out.println(user);returnuser;}
二、DelegatingWebMvcConfiguration
- initWebApplicationContext方法内核心内容就是调用configureAndRefreshWebApplicationContext这个方法
- 看这方法名字中文直译:配置和刷新web容器
- 核心内容就是最后一句,
web容器的刷新
- 容器刷新
抽象类AbstractApplicationContext
的refresh
方法,看过spring源码的应该很熟悉 web容器
和spring容器
都间接继承了AbstractApplicationContext,容器刷新
都调用如下方法- 关于spring的源码Spring源码解析(三):bean容器的刷新之前介绍
容器初始化时候有个很重要的 ps:JDK会自动加载META-INF/services目录下的类(深入理解SPI机制)bean工厂后置处理器ConfigurationClassPostProcessor
,作用就是解析@Configuration,@Import,@ComponentScan,@Bean
等注解给bean容器添加bean定义
,之前文章Spring源码解析(六):bean工厂后置处理器ConfigurationClassPostProcessor有介绍。web容器初始化入口初始化
的工作,例如注册servlet或者filtes等ServletContainerInitializer接口
实现此功能META-INF/services
目录创建一个名为javax.servlet.ServletContainerInitializer
的文件ServletContainerInitializer实现类
容器在启动应用的时候,会扫描当前应用每一个jar包里面META-INF/services指定的实现类(tomcat默认读取)2、
添加过滤器
到Tomcat容器的过滤器集合中
- DispatcherServlet初始化触发了web容器的刷新,加载所有
@Controller
注解的bean
配置拦截器
、加载自定义异常处理器