springMVC初始化
在分析具体的url请求之前,需要了解springMVC环境(spring的web容器)如何进行初始化的
实例代码
package com;
@Configuration
@ComponentScan("com.mvc")
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {
//视图解析
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp( "/app/",".html" );
}
//消息转换
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add( new FastJsonHttpMessageConverter() );
}
}
package com.initializer;
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//初始化spring 容器
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register( AppConfig.class);
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("*.do");
}
}
package com.mvc;
@Component("/name.do")
public class BeanNameController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("beanName---Controller");
return null;
}
}
package com.mvc;
@Component("/name1.do")
public class HandleController implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("beanname-------HttpRequestHandler");
}
}
package com.mvc;
@Controller
public class TestController {
@RequestMapping("/test.do")
@ResponseBody
public Object test(String name, HttpServletRequest request, HttpServletResponse response ){
request.getParameter("name");
Map hashMap = new HashMap();
hashMap.put("key","value");
return hashMap;
}
@RequestMapping("/model.do")
public String model(HttpServletRequest request,HttpServletResponse response){
// /app/index.html
return "index";
}
}
debug分析
springMVC初始化,是从tomcat初始化servlet开始。具体如何开始执行servlet需要tomcat源码。在这里只分析tomcat启动后初始化Servlet在springweb容器的实现流程,从HttpServletBean的init方法开始
HttpServletBean的全路径是org.springframework.web.servlet.HttpServletBean (spring实现)
HttpServlet的全路径是javax.servlet.http.HttpServlet (jdk)
HttpServletBean继承了HttpServlet
init
HttpServletBean#init 初始化方法init
init.png
initServletBean
FrameworkServlet#initServletBean 初始化ServletBean
initServletBean.png
initWebApplicationContext
FrameworkServlet#initWebApplicationContext 初始化WebApplicationContext(web应用上下文---spring形式的web环境)
initWebApplicationContext.png
configureAndRefreshWebApplicationContext
FrameworkServlet#configureAndRefreshWebApplicationContext配置和刷新Refresh web环境
configureAndRefreshWebApplicationContext.png
refresh
AbstractApplicationContext#refresh 这个方法刷新spring web容器
finishBeanFactoryInitialization()方法实例化所有不是lazy的单例对象
refresh.png
实例化
具体的实例化过程经历完整的bean的生命周期,后面再单独介绍。
handlerMap集合添加
对beanName或alias是以/开头
由于BeanNameUrlHandlerMapping实现了ApplicationContextAware方法,会执行initApplicationContext方法
对于beanName是beanNameHandlerMapping
initializeBean
AbstractAutowireCapableBeanFactory#initializeBean(String,Object, RootBeanDefinition)
applyBeanPostProcessorsBeforeInitialization.png
applyBeanPostProcessorsBeforeInitialization
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
applyBeanPostProcessorsBeforeInitialization2.png
postProcessBeforeInitialization
ApplicationContextAwareProcessor#postProcessBeforeInitialization
postProcessBeforeInitialization.png
invokeAwareInterfaces
ApplicationContextAwareProcessor#invokeAwareInterfaces
invokeAwareInterfaces.png
setApplicationContext
ApplicationObjectSupport#setApplicationContext
setApplicationContext.png
initApplicationContext
WebApplicationObjectSupport#initApplicationContext
initApplicationContext.png
initApplicationContext
ApplicationObjectSupport#initApplicationContext(ApplicationContext)
initApplicationContext2.png
initApplicationContext
AbstractDetectingUrlHandlerMapping#initApplicationContext
initApplicationContext3.png
detectHandlers
AbstractDetectingUrlHandlerMapping#detectHandlers
首先通过determineUrlsForHandler方法对beanName判断以/开头(别名或beanName)
determineUrlsForHandler.png
detectHandlers.png
registerHandler
AbstractUrlHandlerMapping#registerHandler(String[], String) 对符合beanName要求的bean进行注册
registerHandler.png
registerHandler
AbstractUrlHandlerMapping#registerHandler(String, Object)
registerHandler2.png
在这里将会对所有beanName以/开头的添加。对实现Controller或HttpRequestHandler的注册
mappingRegistry集合添加
mappingRegistry内部集合其中一个是urlLookup集合
在创建bean过程中,此时对beanName是requestMappingHandlerMapping的处理
由于RequestMappingHandlerMapping实现了InitializingBean方法,所以将会在invokeInitMethods方法处理,在这里便会执行requestMappingHandlerMapping类的afterPropertiesSet方法
initializeBean
AbstractAutowireCapableBeanFactory#initializeBean
initializeBean方法是初始化bean,依次会调用后置处理器的初始化之前方法(applyBeanPostProcessorsBeforeInitialization)、执行初始化方法、后置处理器的初始化之后方法(applyBeanPostProcessorsAfterInitialization)
initializeBean.png
invokeInitMethods
AbstractAutowireCapableBeanFactory#invokeInitMethods执行实现了InitializingBean的afterPropertiesSet方法
invokeInitMethods.png
afterPropertiesSet
RequestMappingHandlerMapping#afterPropertiesSet 此时RequestMappingHandlerMapping已经放到bean工厂里面
afterPropertiesSet.png
afterPropertiesSet
AbstractHandlerMethodMapping#afterPropertiesSet RequestMappingHandlerMapping的父类执行
afterPropertiesSetsuper.png
initHandlerMethods
AbstractHandlerMethodMapping#initHandlerMethods 扫描应用环境的bean,查找并注册Handler的Method
首先判断是否需要从父容器查找,默认是detectHandlerMethodsInAncestorContexts=false。父子容器的含义:如果注册到父容器Handler的Method,在默认false的情况下将不会在父容器查找,这时只在子容器查找将会查找不到。如果设置true,将会从父容器查找,可以查到。
父子容器获取.png
遍历所有的beanName,查找符合isHandler的。带Controller或RequestMapping注解的
isHandler.png
查找Handler的Method(即是Controller的方法)
initHandlerMethods.png
detectHandlerMethods
AbstractHandlerMethodMapping#detectHandlerMethods
detectHandlerMethods.png
对方法遍历用lambda表达式进行注册HandlerMethod
lambda$detectHandlerMethods.png
registerHandlerMethod
AbstractHandlerMethodMapping#registerHandlerMethod 注册到mappingRegistry
registerHandlerMethod.png
register
MappingRegistry#register 添加到urlLookup集合
register.png
到这里完成了对添加了Controller、RequestMapping注解的处理,添加到集合urlLookup。
argumentResolvers初始化
RequestMappingHandlerAdapter 实现了InitializingBean。所以,在实例化RequestMappingHandlerAdapter 过程中,会调用到afterPropertiesSet方法。
RequestMappingHandlerAdapter#afterPropertiesSet
afterPropertiesSet.png
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
argumentResolversSet.png
initBinderArgumentResolvers集合
实现在RequestMappingHandlerAdapter#afterPropertiesSet方法
private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
return resolvers;
}
returnValueHandlers集合
实现在RequestMappingHandlerAdapter#afterPropertiesSet方法
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
initStrategies初始化initXXX集合
通过观察者设计模式实现
包括handlerMappings、handlerAdapters
refresh
finishBeanFactoryInitialization完成实例化之后,调用finishRefresh方法。
finishrefresh.png
finishRefresh
AbstractApplicationContext#finishRefresh 发布ContextRefreshedEvent上下文刷新事件
finishrefresh.png
publishEvent
AbstractApplicationContext#publishEvent(ApplicationEvent) 发布被给的事件给所有的监听者(listeners)
监听者初始化是在MessageSource之后,为了能够在监听器实现访问它,因此MessageSource实现不能发布事件
publishEvent.png
publishEvent
AbstractApplicationContext#publishEvent(Object, ResolvableType)发布被给的事件给所有的监听者(listeners)如果可能的话,使用多播
publishEvent2.png
multicastEvent
SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType) 应用事件多播者广播事件。对所有的符合当前事件类型的监听器进行查找并遍历执行
SAEmulticastEvent.png
invokeListener
SimpleApplicationEventMulticaster#invokeListener 用给定的事件执行给定的监听器
invokeListener.png
doInvokeListener
SimpleApplicationEventMulticaster#doInvokeListener 监听器执行事件
doInvokeListener.png
onApplicationEvent
SourceFilteringListener#onApplicationEvent 具体监听器执行
onApplicationEvent.png
onApplicationEventInternal
SourceFilteringListener#onApplicationEventInternal 根据过滤事件源之后的实际执行事件。如果有的话,默认实现通过调用指定的委托类。
在这里首先要搞清楚SourceFilteringListener#delegate代理类是什么时候被赋值的。在执行refresh()方法之前的addApplicationListener方法。
addApplicationListener.png
创建SourceFilteringListener对象
SourceFilteringListener.png
SourceFilteringListener#onApplicationEventInternal
onApplicationEventInternal.png
onApplicationEvent
GenericApplicationListenerAdapter#onApplicationEvent 委托类执行
onApplicationEvent2.png
onApplicationEvent
ContextRefreshListener#onApplicationEvent 在FrameworkServlet的实例中对于来自servlet的WebApplicationContext(web应用上下文)的ApplicationListener,只委托给onApplicationEvent方法。FrameworkServlet.this是DispatcherServlet
onApplicationEvent3.png
onApplicationEvent
FrameworkServlet#onApplicationEvent 从这个servlet的WebApplicationContext中接收刷新事件的回调。触发刷新这个servlet的上下文相关状态
DSonApplicationEvent.png
onRefresh
DispatcherServlet#onRefresh 刷新应用上下文,这个实现调用initStrategies方法
onRefresh.png
initStrategies
DispatcherServlet#initStrategies 初始化这个servlet使用的策略对象。可以在子类中被覆盖,以便进一步初始化策略。
1、initMultipartResolver
在容器中查找beanName是multipartResolver,类型是MultipartResolver的类。结果返回空
initMultipartResolver.png
2、initLocaleResolver
在容器中查找beanName是localeResolver,类型是LocaleResolver的类。如果返回空,使用默认的AcceptHeaderLocaleResolver
initLocaleResolver.png
3、initThemeResolver
在容器中查找beanName是themeResolver,类型是ThemeResolver的类。如果返回空,使用默认的FixedThemeResolver
initThemeResolver.png
4、initHandlerMappings
DispatcherServlet#initHandlerMappings
从所有容器(父子容器)查找。类型是HandlerMapping的类,默认BeanNameUrlHandlerMapping
initHandlerMappings.png
5、initHandlerAdapters
从所有容器(父子容器)查找。类型是HandlerAdapter的类,默认SimpleControllerHandlerAdapter
initHandlerAdapters.png
6、initHandlerExceptionResolvers
类型是HandlerExceptionResolver
initHandlerExceptionResolvers.png
7、initRequestToViewNameTranslator
在容器中查找beanName是viewNameTranslator 类型是RequestToViewNameTranslator
initRequestToViewNameTranslator.png
8、initViewResolvers
DispatcherServlet#initViewResolvers
initViewResolvers.png
9、initFlashMapManager
返回SessionFlashMapManager
initFlashMapManager.png
@EnableWebMvc注解
在初始化initStrategies过程中,web容器中能够找到那么多不知道什么时候添加的HandlerMapping、HandlerAdapter等等
在实例代码中AppConfig类中使用了EnableWebMvc 注解,源码如下。
开启EnableWebMvc将会导入(import)DelegatingWebMvcConfiguration类,而DelegatingWebMvcConfiguration 继承了WebMvcConfigurationSupport 类。在WebMvcConfigurationSupport 中有18个@Bean方法
package org.springframework.web.servlet.config.annotation;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
package org.springframework.web.servlet.config.annotation;
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
if (useSuffixPatternMatch != null) {
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
mapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
mapping.setPathMatcher(pathMatcher);
}
return mapping;
}
@Bean
public PathMatcher mvcPathMatcher() {
PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
return (pathMatcher != null ? pathMatcher : new AntPathMatcher());
}
@Bean
public UrlPathHelper mvcUrlPathHelper() {
UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
return (pathHelper != null ? pathHelper : new UrlPathHelper());
}
@Bean
public ContentNegotiationManager mvcContentNegotiationManager() {
if (this.contentNegotiationManager == null) {
ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
configurer.mediaTypes(getDefaultMediaTypes());
configureContentNegotiation(configurer);
this.contentNegotiationManager = configurer.buildContentNegotiationManager();
}
return this.contentNegotiationManager;
}
@Bean
public HandlerMapping viewControllerHandlerMapping() {
ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
addViewControllers(registry);
AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
handlerMapping = (handlerMapping != null ? handlerMapping : new EmptyHandlerMapping());
handlerMapping.setPathMatcher(mvcPathMatcher());
handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
handlerMapping.setInterceptors(getInterceptors());
handlerMapping.setCorsConfigurations(getCorsConfigurations());
return handlerMapping;
}
@Bean
public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
mapping.setOrder(2);
mapping.setInterceptors(getInterceptors());
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping;
}
@Bean
public HandlerMapping resourceHandlerMapping() {
Assert.state(this.applicationContext != null, "No ApplicationContext set");
Assert.state(this.servletContext != null, "No ServletContext set");
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper());
addResourceHandlers(registry);
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
if (handlerMapping != null) {
handlerMapping.setPathMatcher(mvcPathMatcher());
handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
handlerMapping.setInterceptors(getInterceptors());
handlerMapping.setCorsConfigurations(getCorsConfigurations());
}
else {
handlerMapping = new EmptyHandlerMapping();
}
return handlerMapping;
}
@Bean
public ResourceUrlProvider mvcResourceUrlProvider() {
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
if (pathHelper != null) {
urlProvider.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
if (pathMatcher != null) {
urlProvider.setPathMatcher(pathMatcher);
}
return urlProvider;
}
@Bean
public HandlerMapping defaultServletHandlerMapping() {
Assert.state(this.servletContext != null, "No ServletContext set");
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
configureDefaultServletHandling(configurer);
HandlerMapping handlerMapping = configurer.buildHandlerMapping();
return (handlerMapping != null ? handlerMapping : new EmptyHandlerMapping());
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
adapter.setCustomArgumentResolvers(getArgumentResolvers());
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
if (jackson2Present) {
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
configureAsyncSupport(configurer);
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;
}
@Bean
public FormattingConversionService mvcConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
addFormatters(conversionService);
return conversionService;
}
@Bean
public Validator mvcValidator() {
Validator validator = getValidator();
if (validator == null) {
if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
Class<?> clazz;
try {
String className = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
clazz = ClassUtils.forName(className, WebMvcConfigurationSupport.class.getClassLoader());
}
catch (ClassNotFoundException | LinkageError ex) {
throw new BeanInitializationException("Failed to resolve default validator class", ex);
}
validator = (Validator) BeanUtils.instantiateClass(clazz);
}
else {
validator = new NoOpValidator();
}
}
return validator;
}
@Bean
public CompositeUriComponentsContributor mvcUriComponentsContributor() {
return new CompositeUriComponentsContributor(
requestMappingHandlerAdapter().getArgumentResolvers(), mvcConversionService());
}
@Bean
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
return new HttpRequestHandlerAdapter();
}
@Bean
public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
return new SimpleControllerHandlerAdapter();
}
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
addDefaultHandlerExceptionResolvers(exceptionResolvers);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
@Bean
public ViewResolver mvcViewResolver() {
ViewResolverRegistry registry = new ViewResolverRegistry(
mvcContentNegotiationManager(), this.applicationContext);
configureViewResolvers(registry);
if (registry.getViewResolvers().isEmpty() && this.applicationContext != null) {
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.applicationContext, ViewResolver.class, true, false);
if (names.length == 1) {
registry.getViewResolvers().add(new InternalResourceViewResolver());
}
}
ViewResolverComposite composite = new ViewResolverComposite();
composite.setOrder(registry.getOrder());
composite.setViewResolvers(registry.getViewResolvers());
if (this.applicationContext != null) {
composite.setApplicationContext(this.applicationContext);
}
if (this.servletContext != null) {
composite.setServletContext(this.servletContext);
}
return composite;
}
}
所以,在导入这个类之后,这些@Bean将会使用配置类的@Bean方法进行处理
beanMethods.png
总结:
本章主要分析,request请求之前的源码级别的初始化过程。
从tomcat初始化init开始加载web级别容器上下文的初始化
1、初始化web容器上下文环境
2、EnableWebMvc注解使用Bean方法,放到web容器中
3、initApplicationContext方法,以/开头的添加到handlerMap集合
4、afterPropertiesSet方法,把Controller、RequestMapping注解方法放到mappingRegistry的集合urlLookup之中
5、argumentResolvers、initBinderArgumentResolvers、returnValueHandlers集合初始化
6、initStrategies策略,对springMVC使用的集合进行赋值。finishRefresh()完成刷新,发布事件。使用观察者设计模式(监听器)
网友评论