SpringMVC源码解析(一):web容器启动流程

avatar
作者
筋斗云
阅读量:38

SpringMVC源码系列文章

SpringMVC源码解析(一):web容器启动流程


目录

一、SpringMVC全注解配置

1、pom文件

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0           	http://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>      <groupId>com.xc.mvc</groupId>     <artifactId>springmvc</artifactId>     <version>1.0-SNAPSHOT</version>      <packaging>war</packaging>      <dependencies>         <!-- SpringMVC -->         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-webmvc</artifactId>             <version>5.3.27</version>         </dependency>          <!-- ServletAPI -->         <dependency>             <groupId>javax.servlet</groupId>             <artifactId>javax.servlet-api</artifactId>             <version>3.1.0</version>             <scope>provided</scope>         </dependency>          <!-- Jackson -->         <dependency>             <groupId>com.fasterxml.jackson.core</groupId>             <artifactId>jackson-databind</artifactId>             <version>2.12.1</version>         </dependency>     </dependencies>      <build>         <plugins>             <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-compiler-plugin</artifactId>                 <configuration>                     <!--配置Maven中Java的编译版本 -->                     <source>1.8</source>                     <target>1.8</target>                 </configuration>             </plugin>         </plugins>     </build> </project> 

2、web容器初始化类(代替web.xml)

/**  * web工程的初始化类,用来代替web.xml  * 以下配置的都是以前在web.xml中配置的  */ public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {     /**      * Spring的配置,目前不涉及Spring,这里设置为空      */     @Override     protected Class<?>[] getRootConfigClasses() {         return new Class<?>[0];     }      /**      * SpringMVC的配置      */     @Override     protected Class<?>[] getServletConfigClasses() {         return new Class<?>[]{SpringMVCConfig.class};     }      /**      * 用于配置DispatcherServlet的映射路径      */     @Override     protected String[] getServletMappings() {         return new String[]{"/"};     }      /**      * 注册过滤器      */     @Override     protected Filter[] getServletFilters() {         // 字符编码过滤器         CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();         characterEncodingFilter.setEncoding("UTF-8");         characterEncodingFilter.setForceEncoding(true);         // HiddenHttpMethodFilter 用于支持 PUT、DELETE 等 HTTP 请求         HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();         return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};     } } 

3、SpringMVC配置类(代替springmvc.xml)

// 将当前类标识为一个配置类 @Configuration // 仅仅扫描@Controller、@RestController @ComponentScan(         value = "com.xc",         includeFilters = {@ComponentScan.Filter(                 type = FilterType.ANNOTATION,                 classes = {Controller.class, RestController.class}         )},         // 默认扫描 @Component @Repository, @Service, or @Controller         useDefaultFilters = false  ) // mvc注解驱动 @EnableWebMvc public class SpringMVCConfig implements WebMvcConfigurer {     // 拦截器     @Override     public void addInterceptors(InterceptorRegistry registry) {         MyInterceptor myInterceptor = new MyInterceptor();         registry.addInterceptor(myInterceptor).addPathPatterns("/**");     } } 

拦截器

public class MyInterceptor implements HandlerInterceptor {     @Override     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {         System.out.println("处理器方法前调用");         return true;     }      @Override     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {         System.out.println("处理器方法后调用");     }      @Override     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {         System.out.println("渲染完成后调用");     } } 

4、测试Controller

// 接受User对象修改并返回 @PostMapping("/test") @ResponseBody public User test(@RequestBody User user) {     // 修改名字为李四然后返回给前台     user.setName("李四");     System.out.println(user);     return user; } 

启动tomcat发送请求结果

在这里插入图片描述

二、SpringServletContainerInitializer

1、web容器初始化入口

  • 在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等
    • servlet规范中通过ServletContainerInitializer接口实现此功能
  • 需要在对应的jar包的META-INF/services目录创建一个名为javax.servlet.ServletContainerInitializer的文件
    • 文件内容指定具体的ServletContainerInitializer实现类

在这里插入图片描述

ps:JDK会自动加载META-INF/services目录下的类(深入理解SPI机制
容器在启动应用的时候,会扫描当前应用每一个jar包里面META-INF/services指定的实现类(tomcat默认读取)

2、SpringServletContainerInitializer的作用解析

  • @HandlesTypes注解作用
    • 获取到所有的实现了WebApplicationInitializer接口的类,然后赋值给onStartup方法的webAppInitializerClasses参数
    • 官方话术为,获取当前类(SpringServletContainerInitializer)感兴趣的类(WebApplicationInitializer)信息
  • 获取到WebApplicationInitializer实现类的Class集合,反射创建对象,遍历调用对象的onStartup方法
// SpringServletContainerInitializer类 @HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { 	@Override 	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) 			throws ServletException {  		List<WebApplicationInitializer> initializers = Collections.emptyList(); 		 		// 如果找不到WebApplicationInitializer的实现类,webAppInitializerClasses就为null 		if (webAppInitializerClasses != null) { 			initializers = new ArrayList<>(webAppInitializerClasses.size()); 			for (Class<?> waiClass : webAppInitializerClasses) { 				// 判断实现类不是接口抽象类,即正常的接口实现类 				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && 						WebApplicationInitializer.class.isAssignableFrom(waiClass)) { 					try { 						// 反射创建对象,并添加到集合中,后面统一遍历调用onStartup方法 						initializers.add((WebApplicationInitializer) 								ReflectionUtils.accessibleConstructor(waiClass).newInstance()); 					} 					catch (Throwable ex) { 						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); 					} 				} 			} 		} 		 		// 集合为空,证明没找到实现类,直接返回 		if (initializers.isEmpty()) { 			servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); 			return; 		} 		 		// 排序,证明WebApplicationInitializer的实现类有先后顺序 		AnnotationAwareOrderComparator.sort(initializers); 		for (WebApplicationInitializer initializer : initializers) { 			// 调用WebApplicationInitializer接口实现类的onStartup方法 			initializer.onStartup(servletContext); 		} 	} }  // WebApplicationInitializer接口 public interface WebApplicationInitializer { 	/** 	 * 初始化此Web应用程序所需的任何Servlet、过滤器、侦听器上下文参数和属性配置给定的ServletContext 	 */ 	void onStartup(ServletContext servletContext) throws ServletException; } 

WebApplicationInitializer接口与自定义配置类WebAppInitalizer(代替web.xml)关系

  • WebApplicationInitializer初始化核心接口,onStartup方法初始化Servelt、过滤器等
  • WebAppInitalizer即为WebApplicationInitializer的实现类,也就是SpringServletContainerInitializer要找的感兴趣的类,获取到多个放到集合initializer中,然后排序,最后遍历调用onStartup方法

在这里插入图片描述

  总结SpringServletContainerInitializer作用:加载自定义的WebApplicationInitializer初始化核心接口的实现类WebAppInitializer,调用onStartup方法来实现web容器初始化。

在这里插入图片描述

三、自定义配置类的加载

自定义配置类WebAppInitializer(代替web.xml)的类图如下:

在这里插入图片描述
  由上一节可知,web容器初始化工作会调用自定义配置类的onStartup方法,那就是根据类图从下往上找onStartup方法调用,WebAppInitializer和AbstractAnnotationConfigDispatcherServletInitializer中都没有onStartup方法,那么首先进入AbstractDispatcherServletInitializer重写的onStartup方法,核心内容注册前端控制器

在这里插入图片描述

1、AbstractDispatcherServletInitializer注册前端控制器

  • getServletMappings():调用自定义配置类配置DispatcherServlet的映射路径的方法
  • getServletFilters():调用自定义配置类注册过滤器的方法
// AbstractDispatcherServletInitializer类的方法 protected void registerDispatcherServlet(ServletContext servletContext) { 	// 获取servlet名称,常量“dispatcher” 	String servletName = getServletName(); 	// 创建一个web应用程序子容器 	WebApplicationContext servletAppContext = createServletApplicationContext(); 	// 创建DispatcherServlet对象,将上下文设置到dispatcherServlet中 	FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext); 	// 设置servlet容器初始化参数(这里不设置一般默认为null)  	dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers()); 	// 把servlet添加到Tomcat容器中 	ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); 	if (registration == null) { 		throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " + 				"Check if there is another servlet registered under the same name."); 	} 	// 将前端控制器初始化提前到服务器启动时,否则调用时才会初始化 	registration.setLoadOnStartup(1); 	// 添加servlet映射,拦截请求 	// 调用自定义配置类重写的getServletMappings方法 	registration.addMapping(getServletMappings()); 	// 设置是否支持异步,默认true 	registration.setAsyncSupported(isAsyncSupported()); 	 	// 获取所有的过滤器getServletFilters方法 	// 调用自定义配置类重写的getServletMappings方法 	Filter[] filters = getServletFilters(); 	if (!ObjectUtils.isEmpty(filters)) { 		for (Filter filter : filters) { 			registerServletFilter(servletContext, filter); 		} 	} 	// 空方法,可以再对dispatcherServlet进行处理 	customizeRegistration(registration); } 

1.1、创建web注解容器

  • getServletConfigClasses():调用自定义配置类配置SpringMVC配置的方法
// AbstractAnnotationConfigDispatcherServletInitializer类方法 protected WebApplicationContext createServletApplicationContext() { 	AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); 	// 调用自定义配置类的设置子容器配置文件的方法 	Class<?>[] configClasses = getServletConfigClasses(); 	if (!ObjectUtils.isEmpty(configClasses)) { 		context.register(configClasses); 	} 	return context; } 

1.2、创建DispatcherServlet对象

  • 创建DispatcherServlet对象,传入web容器
// AbstractDispatcherServletInitializer类方法 protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) { 	return new DispatcherServlet(servletAppContext); } 

1.3、注册过滤器

  • 将过滤器添加到Tomcat容器的过滤器集合中
protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) { 	String filterName = Conventions.getVariableName(filter); 	Dynamic registration = servletContext.addFilter(filterName, filter);  	...  	registration.setAsyncSupported(isAsyncSupported()); 	registration.addMappingForServletNames(getDispatcherTypes(), false, getServletName()); 	return registration; } 

在这里插入图片描述

小结一下

  • 目前为止代替web.xml的配置类中内容加载完成
    • 创建web注解容器,此时只是创建出来,还没有初始化
    • 创建DispatcherServlet并设置映射路径
    • 注册过滤器
  • 接下来的入口在DispatcherServlet这里,因为其本质是Servlet,那么就会涉及到Tomcat初始化Servelt

2、DispatcherServlet初始化

DispatcherServlet类图如下:

在这里插入图片描述

  Tomcat启动容器加载Servelt(这里是DispatcherServlet)并初始化,就会调用到这里。之前文章Tomcat源码解析(五):StandardEngine、StandardHost、StandardContext、StandardWrapper中有介绍。

在这里插入图片描述

  • initWebApplicationContext方法内核心内容就是调用configureAndRefreshWebApplicationContext这个方法
  • 看这方法名字中文直译:配置和刷新web容器
  • 核心内容就是最后一句,web容器的刷新

在这里插入图片描述

  • 容器刷新抽象类AbstractApplicationContextrefresh方法,看过spring源码的应该很熟悉
  • web容器spring容器都间接继承了AbstractApplicationContext,容器刷新都调用如下方法
  • 关于spring的源码Spring源码解析(三):bean容器的刷新之前介绍

在这里插入图片描述

  容器初始化时候有个很重要的bean工厂后置处理器ConfigurationClassPostProcessor,作用就是解析@Configuration,@Import,@ComponentScan,@Bean等注解给bean容器添加bean定义,之前文章Spring源码解析(六):bean工厂后置处理器ConfigurationClassPostProcessor有介绍。

  接下来的入口就在自定义g配置类SpringMVCConfi这里,因为它的配置类注解@Configuration(也是@Component),@ComponentScan(扫描@Controller注解)@EnableWebMvc(导入DelegatingWebMvcConfiguration.class)注解都会被扫描解析到。

在这里插入图片描述

四、@EnableWebMvc解析

@EnableWebMvc

在这里插入图片描述

1、WebMvcConfigurer接口

  在讲DelegatingWebMvcConfiguration之前先说下WebMvcConfigurer接口,因为下面内容都是围绕着WebMvcConfigurer接口展开的。

  WebMvcConfigurer是一个接口,它提供了一种扩展SpringMVC配置的方式。通过实现WebMvcConfigurer接口,可以定制化SpringMVC的配置例如添加拦截器、跨域设置、方法参数解析器、返回值处理、消息转换器、异常处理器

public interface WebMvcConfigurer { 	... 	 	// 配置拦截器 	default void addInterceptors(InterceptorRegistry registry) { 	}  	// 配置跨域 	default void addCorsMappings(CorsRegistry registry) { 	}  	// 配置视图解析器 	default void configureViewResolvers(ViewResolverRegistry registry) { 	} 	 	// 配置方法参数解析器(解析@RequestBody就是通过HandlerMethodArgumentResolver接口实现的) 	default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { 	}  	// 配置方法返回值(解析@ResponseBody就是通过HandlerMethodReturnValueHandler接口实现的) 	default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) { 	}  	// 配置消息转换器(此时可能还没有转换器) 	default void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 	} 	 	// 扩展消息转换器(至少已存在默认转换器) 	default void extendMessageConverters(List<HttpMessageConverter<?>> converters) { 	}  	// 配置异常处理器 	default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { 	} 	 	... } 

2、DelegatingWebMvcConfiguration

DelegatingWebMvcConfiguration的类图如下:
在这里插入图片描述

  • 如果开发者或者第三方想要配置拦截器、消息转换器的等配置,只要实现WebMvcConfigurer接口重写对应方法即可
  • 通过setConfigurers方法讲所有WebMvcConfigurer接口实现类注入进来,放入configurers的List<WebMvcConfigurer> delegates属性中
  • 下面会讲到什么时候触发调用DelegatingWebMvcConfiguration中重写的MVC配置方法
@Configuration(proxyBeanMethods = false) public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { 	// WebMvcConfigurerComposite实现WebMvcConfigurer,内部有个WebMvcConfigurer集合 	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();  	// 注入一组WebMvcConfigurer,这些WebMvcConfigurer由开发人员提供,或者框架其他部分提供 	@Autowired(required = false) 	public void setConfigurers(List<WebMvcConfigurer> configurers) { 		if (!CollectionUtils.isEmpty(configurers)) { 			this.configurers.addWebMvcConfigurers(configurers); 		} 	} 	 	... 	 	// 如下方法都是重写父类WebMvcConfigurationSupport 	// 与WebMvcConfigurer接口中的方法一样,配置拦截器、跨域配置等 	@Override 	protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 		this.configurers.configureDefaultServletHandling(configurer); 	}  	@Override 	protected void addInterceptors(InterceptorRegistry registry) { 		this.configurers.addInterceptors(registry); 	}  	@Override 	protected void addCorsMappings(CorsRegistry registry) { 		this.configurers.addCorsMappings(registry); 	}  	@Override 	protected void configureViewResolvers(ViewResolverRegistry registry) { 		this.configurers.configureViewResolvers(registry); 	}  	@Override 	protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 		this.configurers.configureMessageConverters(converters); 	}  	@Override 	protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { 		this.configurers.configureHandlerExceptionResolvers(exceptionResolvers); 	}  	... } 

  调用DelegatingWebMvcConfiguration重写的MVC配置方法实际就是对应的配置添加到对应的注册器中。如所有的拦截器都会被添加到InterceptorRegistry(拦截器注册器)、所有跨域配置则会被添加到CorsRegistry(跨域注册器),不用说对应的注册器中肯定维护着对应的配置集合。

// WebMvcConfigurerComposite类 class WebMvcConfigurerComposite implements WebMvcConfigurer { 	private final List<WebMvcConfigurer> delegates = new ArrayList<>(); 	 	@Override 	public void addInterceptors(InterceptorRegistry registry) { 		for (WebMvcConfigurer delegate : this.delegates) { 			delegate.addInterceptors(registry); 		} 	} 	@Override 	public void addCorsMappings(CorsRegistry registry) { 		for (WebMvcConfigurer delegate : this.delegates) { 			delegate.addCorsMappings(registry); 		} 	} 	@Override 	public void configureViewResolvers(ViewResolverRegistry registry) { 		for (WebMvcConfigurer delegate : this.delegates) { 			delegate.configureViewResolvers(registry); 		} 	} 	@Override 	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 		for (WebMvcConfigurer delegate : this.delegates) { 			delegate.configureMessageConverters(converters); 		} 	} } 

3、WebMvcConfigurationSupport(🔥重点)

  在上面说到WebMvcConfigurationSupport类中定义了与WebMvcConfigurer接口一样的配置方法,都是空实现,由子类DelegatingWebMvcConfiguration重写,遍历所有WebMvcConfigurer的实现类,将对应配置添加到对应注册器中。

  另外一方面在WebMvcConfigurationSupport类中有很多@Bean方法,即bean定义,返回值即为创建的bean对象。其中有两个很重要,映射器RequestMappingHandlerMapping适配器RequestMappingHandlerAdapter

3.1、处理器映射器和处理器适配器

映射器HandlerMapping

public interface HandlerMapping { 	/** 	 * 获取执行器链(包括Handler和拦截器) 	 */ 	@Nullable 	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; } 
  • HandlerMapping映射器作用:主要是根据request请求匹配/映射上能够处理当前request的Handler
  • 定义Handler的方式有很多
    • 最常用的@Controller,结合@RequestMapping("/test")
    • 实现Controller接口,实现handleRequest方法,结合@Component(“/test”)
    • 实现HttpRequestHandler接口,实现handleRequest方法,结合@Component(“/test”)
  • 以上三种方式都需要生成请求和Handler的映射
    • 所以抽象出一个接口:HandlerMapping,有很多实现类
    • @RequestMapping注解的Handler使用RequestMappingHandlerMapping处理
    • 其他方式会使用BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping

适配器HandlerAdapter

public interface HandlerAdapter {  	/** 	 * 因为有多个HandlerMapping和HandlerAdapter 	 * 对于HandlerAdapter是否支持对应的HandlerMapping,通过此方法判断 	 */ 	boolean supports(Object handler);  	/** 	 * 具体调用Hangder的方法 	 */ 	@Nullable 	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; } 
  • 上一步中不同映射器通过请求映射到的Handler不确定类型
    • @RequestMapping注解方式获取到的是具体的Method
    • 其他实现接口方式获取到的是具体的Class
  • 此时拿到Handler去执行具体的方法时候,方式是不统一
  • 那么适配器就出现了
  • RequestMappingHandlerAdapter就是处理@RequestMapping注解的Handler

3.2、RequestMappingHandlerMapping映射器

  • 一句话解释它:解析@RequestMapping注解
3.2.1、实例化
// WebMvcConfigurationSupport类方法 @Bean @SuppressWarnings("deprecation") public RequestMappingHandlerMapping requestMappingHandlerMapping( 		@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, 		@Qualifier("mvcConversionService") FormattingConversionService conversionService, 		@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) { 	// 创建RequestMappingHandlerMapping对象 	RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); 	// 设置排序为0,以后会遍历所有HandlerMapping,排序0的话,则会先遍历 	// 简单说@RequestMaping注解使用概率大,先用RequestMappingHandlerMapping处理 	mapping.setOrder(0); 	// 设置所有的拦截器,并排序 	mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider)); 	mapping.setContentNegotiationManager(contentNegotiationManager); 	// 设置所有的跨域配置 	mapping.setCorsConfigurations(getCorsConfigurations());  	// 省略各种匹配url的属性,如url正则匹配等等,我们这次只考虑url正常匹配 	...  	return mapping; } 
3.2.1.1、获取所有拦截器

  这里先创建拦截器注册器InterceptorRegistry,然后调用DelegatingWebMvcConfiguration重写WebMvcConfigurationSupport的添加拦截器方法addInterceptors,这样所有拦截器就都会被添加到InterceptorRegistry registry中。最后将我们自定义的拦截器组成MappedInterceptor

// WebMvcConfigurationSupport protected final Object[] getInterceptors( 		FormattingConversionService mvcConversionService, 		ResourceUrlProvider mvcResourceUrlProvider) {  	if (this.interceptors == null) { 		InterceptorRegistry registry = new InterceptorRegistry(); 		// 这里就是调用DelegatingWebMvcConfiguration重写的方法 		addInterceptors(registry); 		// 这是两个设置setAttribute值的拦截器,不用深入研究 		registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService)); 		registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider)); 		// 这里会将上面我们自己设置的拦截器包装一层返回 		this.interceptors = registry.getInterceptors(); 	} 	return this.interceptors.toArray(); } 

  这里将我们所有自定义拦截器都这样包装一层,因为是以后为了统一管理,这个MappedInterceptor拦截器里面有个很重要方法matches(此次请求是否匹配当前拦截器),就是筛选拦截器链使用的。

在这里插入图片描述

3.2.1.2、获取所有跨域配置

  也是先创建跨域注册器CorsRegistry,然后调用然后调用DelegatingWebMvcConfiguration重写WebMvcConfigurationSupport的添加跨域方法addCorsMappings,也是添加到CorsRegistry registry中。

// WebMvcConfigurationSupport protected final Map<String, CorsConfiguration> getCorsConfigurations() { 	if (this.corsConfigurations == null) { 		CorsRegistry registry = new CorsRegistry(); 		addCorsMappings(registry); 		this.corsConfigurations = registry.getCorsConfigurations(); 	} 	return this.corsConfigurations; } 
3.2.2、初始化

RequestMappingHandlerMapping的复杂类图看一下(有删减)

  @RequestMapping注解肯定是在容器启动时候解析的,那么这个工作就放在RequestMappingHandlerMapping这个bean对象的初始化阶段来完成。之前文章Spring源码解析(四):单例bean的创建流程有介绍过,bean对象创建后会调用各种初始化方法,其实就包括调用InitializingBean接口afterPropertiesSet方法来实现初始化

在这里插入图片描述

  • RequestMappingHandlerMapping实现了afterPropertiesSet方法如下
// RequestMappingHandlerMapping类方法 @Override @SuppressWarnings("deprecation") public void afterPropertiesSet() { 	// 创建RequestMappingInfo对象 	this.config = new RequestMappingInfo.BuilderConfiguration(); 	this.config.setTrailingSlashMatch(useTrailingSlashMatch()); 	this.config.setContentNegotiationManager(getContentNegotiationManager());  	if (getPatternParser() != null) { 		this.config.setPatternParser(getPatternParser()); 		Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch, 				"Suffix pattern matching not supported with PathPatternParser."); 	} 	else { 		this.config.setSuffixPatternMatch(useSuffixPatternMatch()); 		this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch()); 		this.config.setPathMatcher(getPathMatcher()); 	} 	// 调用父类实现的afterPropertiesSet方法 	super.afterPropertiesSet(); } 
  • 父类AbstractHandlerMethodMapping实现了afterPropertiesSet方法如下
// AbstractHandlerMethodMapping类方法  /**  * 在初始化时检测处理程序方法  */ @Override public void afterPropertiesSet() { 	initHandlerMethods(); }  /**  * 扫描 ApplicationContext 中的 Bean,检测并注册处理程序方法  */ protected void initHandlerMethods() { 	// 获取所有的bean对象并遍历 	for (String beanName : getCandidateBeanNames()) { 		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { 			// 筛选候选的bean 			processCandidateBean(beanName); 		} 	} 	// getHandlerMethods()获取请求路径与具体Controller方法的映射关系 	handlerMethodsInitialized(getHandlerMethods()); } 
3.2.2.1、获取候选bean
// AbstractHandlerMethodMapping类方法 protected void processCandidateBean(String beanName) { 	Class<?> beanType = null; 	try { 		// 获取bean对象的Class类型 		beanType = obtainApplicationContext().getType(beanName); 	} 	catch (Throwable ex) { 		... 	} 	// 判断是否处理程序 	if (beanType != null && isHandler(beanType)) { 		// 查找处理程序的方法 		detectHandlerMethods(beanName); 	} } 
  • 根据类上@Controller@RequestMapping注解判断是否为处理程序
// RequestMappingHandlerMapping @Override protected boolean isHandler(Class<?> beanType) { 	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || 			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); } 
  • 查询处理程序的方法
    1. 此时获取到的handler已经确定有@Controller或者@RequestMapping
    2. 遍历handler类下所有的Method
      • 判断Method方法上是否有@RequestMapping注解
      • 有注解则将注解内的属性包装成一个类:RequestMappingInfo
    3. 返回一个map集合methods
      • key为有@RequestMapping注解的Method对象
      • value为RequestMappingInfo对象
// AbstractHandlerMethodMapping类方法 protected void detectHandlerMethods(Object handler) { 	Class<?> handlerType = (handler instanceof String ? 			obtainApplicationContext().getType((String) handler) : handler.getClass());  	if (handlerType != null) { 		// 类如果被代理,获取真正的类型 		Class<?> userType = ClassUtils.getUserClass(handlerType); 		Map<Method, T> methods = MethodIntrospector.selectMethods(userType, 				(MethodIntrospector.MetadataLookup<T>) method -> { 					try { 						return getMappingForMethod(method, userType); 					} 					catch (Throwable ex) { 						... 					} 				}); 		...		 		 		// 注册Handler方法(将请求路径、RequestMappingInfo、Controller#Method统一放一起) 		methods.forEach((method, mapping) -> { 			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); 			registerHandlerMethod(handler, invocableMethod, mapping); 		}); 	} } // RequestMappingHandlerMapping类方法 @Override @Nullable protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { 	RequestMappingInfo info = createRequestMappingInfo(method); 	... 	return info; } 
  • getMappingForMethod方法的实现就交给具体子类RequestMappingHandlerMapping了
  • getMappingForMethod方法核心内容:筛选Controller类@RequestMapping注解方法

在这里插入图片描述

registerHandlerMethod:注册Handler方法(将请求路径、RequestMappingInfo、Controller#Method统一放到MappingRegistry对象中)

  • 核心方法为AbstractHandlerMethodMapping抽象类的内部类MappingRegistry类的register方法
// AbstractHandlerMethodMapping的内部类MappingRegistry类方法 class MappingRegistry {  	private final Map<T, MappingRegistration<T>> registry = new HashMap<>(); 	private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>(); 	private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>(); 		 	public void register(T mapping, Object handler, Method method) { 		this.readWriteLock.writeLock().lock(); 		try { 			// handler(Controller对象)与有@RequestMapping的Method组成对象HandlerMethod 			HandlerMethod handlerMethod = createHandlerMethod(handler, method); 			// 校验@RequestMapping注解内容是否注册过 			validateMethodMapping(handlerMethod, mapping); 			 			// 获取@RequestMapping注解映射的路径,因为可以设置多个,所以这里是集合 			Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping); 			for (String path : directPaths) { 				this.pathLookup.add(path, mapping); 			} 	 			... 			 			// 获取@CrossOrigin获取CorsConfiguration,并初始化跨域的默认值,最后跨域配置添加到corsLookup 			CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); 			if (corsConfig != null) { 				corsConfig.validateAllowCredentials(); 				this.corsLookup.put(handlerMethod, corsConfig); 			} 			 			// 各类属性配置组成对象MappingRegistration,然后添加到registry中 			this.registry.put(mapping, 					new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null)); 		} 		finally { 			this.readWriteLock.writeLock().unlock(); 		} 	} } 
  • MappingRegistry(映射注册器),以后的mapping映射什么都放这里
    • MultiValueMap<String, T> pathLookup
      • key为@RequestMapping注解的映射路径
      • value为RequestMappingInfo对象(@RequestMapping注解属性组成的对象)
    • Map<HandlerMethod, CorsConfiguration> corsLookup
      • key为HandlerMethod
      • value为解析@CrossOrigin注解的跨域配置
    • Map<T, MappingRegistration> registry
      • key为RequestMappingInfo对象
      • value为MappingRegistration对象(RequestMappingInfo、HandlerMethod、CorsConfiguration组成的对象)
  • 校验RequestMappingInfo(@RequestMapping属性对象)是否存在
    • 存在的话这里就会抛出异常There is already 'xxx' bean method(这个大家应该很熟悉)
  • 注意:以上步骤都是在readWriteLock锁内完成的,以防多个线程注册映射对象重复
3.2.2.2、获取HandlerMethod并统计数量
  • 从mappingRegistry中获取map集合即为上面所说MappingRegistry对象的registry属性
// AbstractHandlerMethodMapping类方法 public Map<T, HandlerMethod> getHandlerMethods() { 	this.mappingRegistry.acquireReadLock(); 	try { 		return Collections.unmodifiableMap( 				this.mappingRegistry.getRegistrations().entrySet() 				.stream().collect(Collectors.toMap( 					Map.Entry::getKey,  					entry -> entry.getValue().handlerMethod) 				)); 	} 	finally { 		this.mappingRegistry.releaseReadLock(); 	} } 
  • 获取到上面拿到的handlerMethods,打印数量
protected void handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods) { 	// 获取到上面拿到的值,打印数量 	int total = handlerMethods.size(); 	if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) { 		logger.debug(total + " mappings in " + formatMappingName()); 	} } 

3.3、RequestMappingHandlerAdapter适配器

  • 一句话解释它:拿到RequestMappingHandlerMapping解析出的HandlerMethod去调用具体的Method
3.3.1、实例化
// WebMvcConfigurationSupport类方法  private static final boolean jackson2Present; // 加载对应的类,能加载成功方true,不能加载成功,表示没有这个类,没有导入包,返回false jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && 				ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);   @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter( 		@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, 		@Qualifier("mvcConversionService") FormattingConversionService conversionService, 		@Qualifier("mvcValidator") Validator validator) { 	// 创建RequestMappingHandlerAdapter对象 	RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); 	adapter.setContentNegotiationManager(contentNegotiationManager); 	// 设置消息转换器 	adapter.setMessageConverters(getMessageConverters()); 	adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator)); 	adapter.setCustomArgumentResolvers(getArgumentResolvers()); 	adapter.setCustomReturnValueHandlers(getReturnValueHandlers()); 	 	// 如果导入Jackson包,则添加 	if (jackson2Present) { 		// 处理jackson中的@JsonView的字段,过滤输出的字段,具体实现以后单独讲 		adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice())); 		adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice())); 	}  	// 省略异步配置,以后再研究 	...  	return adapter; } 
3.3.1.1、获取消息转换器

  先调用DelegatingWebMvcConfiguration重写的方法,也就是遍历所有WebMvcConfigurer实现类,调用他们的configureMessageConverters方法,新增的消息转换器都会添加到messageConverters集合中。如果开发者和第三方都没有添加,那么设置默认的消息转换器,设置完以后,再调用扩展方法,也就是遍历所有WebMvcConfigurer实现类,调用他们的extendMessageConverters方法,对消息转换器做最后修改

// WebMvcConfigurationSupport protected final List<HttpMessageConverter<?>> getMessageConverters() { 	if (this.messageConverters == null) { 		this.messageConverters = new ArrayList<>(); 		// 这里就是调用DelegatingWebMvcConfiguration重写的方法,配置消息转换器 		configureMessageConverters(this.messageConverters); 		if (this.messageConverters.isEmpty()) { 			// 如果上面没有添加消息转换器,这里添加默认的消息转换器 			addDefaultHttpMessageConverters(this.messageConverters); 		} 		// 这里就是调用DelegatingWebMvcConfiguration重写的方法,扩展消息转化器 		extendMessageConverters(this.messageConverters); 	} 	return this.messageConverters; } 

  加载jackson里的类,能加载成功jackson2Present返回true,不能加载成功,表示没有这个类,没有导入包,返回jackson2Present返回false,然后去判断是否导入Google、JDK自带的处理JSON类。一般我们会导入Jackson,那么这里会添加MappingJackson2HttpMessageConverter消息转换器。

// WebMvcConfigurationSupport类方法 protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) { 	// 默认消息转换器 	messageConverters.add(new ByteArrayHttpMessageConverter()); 	messageConverters.add(new StringHttpMessageConverter()); 	messageConverters.add(new ResourceHttpMessageConverter()); 	messageConverters.add(new ResourceRegionHttpMessageConverter());  	... 	 	// jackson 	if (jackson2Present) { 		Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); 		if (this.applicationContext != null) { 			builder.applicationContext(this.applicationContext); 		} 		messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); 	} 	// Google Gson 库中的一个核心类,Java对象与JSON 格式字符串进行相互转换 	else if (gsonPresent) { 		messageConverters.add(new GsonHttpMessageConverter()); 	} 	// JDK 类库JSON类 	else if (jsonbPresent) { 		messageConverters.add(new JsonbHttpMessageConverter()); 	}  	... } 
3.3.2、初始化

RequestMappingHandlerAdapter的类图如下(有删减)

  与RequestMappingHandlerMapping一样,RequestMappingHandlerAdapter对象初始化就会调用InitializingBean接口afterPropertiesSet方法来实现初始化

在这里插入图片描述

  • RequestMappingHandlerAdapter实现了afterPropertiesSet方法如下
// RequestMappingHandlerAdapter类方法 @Override public void afterPropertiesSet() { 	// 初始化@ControllerAdvice 	initControllerAdviceCache(); 	 	// 设置默认的方法参数解析器 	if (this.argumentResolvers == null) { 		List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); 		this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); 	} 	if (this.initBinderArgumentResolvers == null) { 		List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); 		this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); 	} 	// 设置默认的返回值处理器 	if (this.returnValueHandlers == null) { 		List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); 		this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); 	} } 
3.3.2.1、初始化@ControllerAdvice
  • 遍历所有的bean对象,获取有@ControllerAdvice注解的bean
  • 通过@ControllerAdvice内容和bean名称创建对象ControllerAdviceBean,添加到集合中
  • 再从集合中筛选出bean对象实现接口RequestBodyAdviceResponseBodyAdvice
    • RequestBodyAdvice请求增强器:允许请求体被读取并转换为对象
    • ResponseBodyAdvice响应增强器:允许在执行@ResponseBody后自定义返回数据
// RequestMappingHandlerAdapter类方法 private void initControllerAdviceCache() { 	if (getApplicationContext() == null) { 		return; 	} 	 	// 获取所有@ControllerAdvice注解的bean,创建成ControllerAdviceBean对象的集合 	List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());  	List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();  	for (ControllerAdviceBean adviceBean : adviceBeans) { 		Class<?> beanType = adviceBean.getBeanType(); 		if (beanType == null) { 			throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); 		} 		 		...		 		 		// 筛选实现RequestBodyAdvice或ResponseBodyAdvice的adviceBean 		if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) { 			requestResponseBodyAdviceBeans.add(adviceBean); 		} 	}  	if (!requestResponseBodyAdviceBeans.isEmpty()) { 		this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans); 	}  	... }  public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) { 	ListableBeanFactory beanFactory = context; 	if (context instanceof ConfigurableApplicationContext) { 		beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory(); 	} 	List<ControllerAdviceBean> adviceBeans = new ArrayList<>(); 	// 遍历所有的bean对象 	for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Object.class)) { 		if (!ScopedProxyUtils.isScopedTarget(name)) { 			// 寻找有@ControllerAdvice注解 			ControllerAdvice controllerAdvice = beanFactory.findAnnotationOnBean(name, ControllerAdvice.class); 			if (controllerAdvice != null) { 				// 创建ControllerAdviceBean对象添加到集合中 				adviceBeans.add(new ControllerAdviceBean(name, beanFactory, controllerAdvice)); 			} 		} 	} 	OrderComparator.sort(adviceBeans); 	return adviceBeans; } 
3.3.2.2、HandlerMethodArgumentResolver方法参数解析器
public interface HandlerMethodArgumentResolver {  	/** 	 * 此解析器是否支持给定的方法参数 	 */ 	boolean supportsParameter(MethodParameter parameter);  	/** 	 * 将方法参数解析为给定请求的参数值 	 */ 	@Nullable 	Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, 			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;  } 
  • 方法参数解析器有很多,差不多一个注解就对应一个参数解析器

在这里插入图片描述

3.3.2.3、HandlerMethodReturnValueHandler返回值处理器
public interface HandlerMethodReturnValueHandler {  	/**      * 此处理程序是否支持给定的方法返回类型 	 */ 	boolean supportsReturnType(MethodParameter returnType);  	/** 	 * 通过向模型添加属性并设置视图或设置 	 */ 	void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, 			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;  } 
  • 返回值处理器也有很多,我们只研究熟悉常用的就可以

在这里插入图片描述

  • RequestResponseBodyMethodProcessor类既是@RequestBody解析器又是@ResponseBody解析器

在这里插入图片描述

  对应方法参数解析器和返回值处理器这里就不展开说了,只要知道项目启动会加载这些东西即可,下一篇文章请求的执行流程再进入源码研究。

3.4、HandlerExceptionResolver异常处理器

  • 一句话解释它:Hander异常抛错后调用的方法

  与消息转换器很像,先遍历所有WebMvcConfigurer实现类configureHandlerExceptionResolvers中新增的异常处理器,如果没有开发者或者第三方新增,那么添加默认的的异常处理器,再调用扩展方法,也就是遍历所有WebMvcConfigurer实现类,调用他们的extendHandlerExceptionResolvers方法,对异常处理器做最后修改

// WebMvcConfigurationSupport类方法 @Bean public HandlerExceptionResolver handlerExceptionResolver( 		@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) { 	// 创建空集合 	List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>(); 	// 这里就是调用DelegatingWebMvcConfiguration重写的方法 	// 其实就是寻找WebMvcConfigurer实现类是否添加异常处理器 	configureHandlerExceptionResolvers(exceptionResolvers); 	if (exceptionResolvers.isEmpty()) { 		addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager); 	} 	// 这里就是调用DelegatingWebMvcConfiguration重写的方法,扩展异常处理器 	extendHandlerExceptionResolvers(exceptionResolvers); 	HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite(); 	composite.setOrder(0); 	composite.setExceptionResolvers(exceptionResolvers); 	return composite; } 
  • ExceptionHandlerExceptionResolver:这个异常处理器内包含所有的自定义异常处理器
    • 因为这个对象不是bean对象,这里手动调用初始化接口的方法afterPropertiesSet
  • 最后添加默认异常处理器DefaultHandlerExceptionResolver
protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers, 		ContentNegotiationManager mvcContentNegotiationManager) { 	// 这个异常处理器内包含所有的自定义异常处理器 	ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver(); 	exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager); 	exceptionHandlerResolver.setMessageConverters(getMessageConverters()); 	exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers()); 	exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers()); 	if (jackson2Present) { 		exceptionHandlerResolver.setResponseBodyAdvice( 				Collections.singletonList(new JsonViewResponseBodyAdvice())); 	} 	if (this.applicationContext != null) { 		exceptionHandlerResolver.setApplicationContext(this.applicationContext); 	} 	// 手动调用初始化接口的初始化方法 	exceptionHandlerResolver.afterPropertiesSet(); 	exceptionResolvers.add(exceptionHandlerResolver); 	 	// ResponseStatus异常处理器 	ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver(); 	responseStatusResolver.setMessageSource(this.applicationContext); 	exceptionResolvers.add(responseStatusResolver); 	// 默认异常处理器 	exceptionResolvers.add(new DefaultHandlerExceptionResolver()); } 
3.4.1、加载自定义异常处理器
// ExceptionHandlerExceptionResolver类方法 @Override public void afterPropertiesSet() { 	// 初始化异常处理增强类 	initExceptionHandlerAdviceCache();  	if (this.argumentResolvers == null) { 		List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); 		this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); 	} 	if (this.returnValueHandlers == null) { 		List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); 		this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); 	} } 
  • 筛选异常处理器类:@ControllerAdvice类且方法上存在@ExceptionHandler
// ExceptionHandlerExceptionResolver类方法 private void initExceptionHandlerAdviceCache() { 	if (getApplicationContext() == null) { 		return; 	} 	// 获取所有@ControllerAdvice注解的bean,创建成ControllerAdviceBean,添加到集合中 	List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); 	for (ControllerAdviceBean adviceBean : adviceBeans) { 		Class<?> beanType = adviceBean.getBeanType(); 		if (beanType == null) { 			throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); 		} 		// 筛选方法上@ExceptionHandler注解 		ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType); 		if (resolver.hasExceptionMappings()) { 			this.exceptionHandlerAdviceCache.put(adviceBean, resolver); 		} 		if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) { 			this.responseBodyAdvice.add(adviceBean); 		} 	} }  // ExceptionHandlerMethodResolver类属性和方法 public static final MethodFilter EXCEPTION_HANDLER_METHODS = method -> 		AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class);  public ExceptionHandlerMethodResolver(Class<?> handlerType) { 	for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) { 		for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) { 			addExceptionMapping(exceptionType, method); 		} 	} } 

  至此,SpringMVC启动重要的组件都介绍完毕。

总结

  • 加载继承AbstractAnnotationConfigDispatcherServletInitializer的MVC配置类(开发者创建,代替web.xml)
  • 既然代替web.xml那么这个配置类可以设置DispatcherServlet的映射路径注册过滤器
  • 父类AbstractAnnotationConfigDispatcherServletInitializer里面会创建web注解容器创建DispatcherServlet对象添加过滤器到Tomcat容器的过滤器集合中
    • DispatcherServlet初始化触发了web容器的刷新,加载所有@Controller注解的bean
  • 如果开发者或者第三方想要配置拦截器消息转换器的等配置,只要实现WebMvcConfigurer接口重写对应方法即可
  • 解析@RequestMapping注解(根据注解属性创建对象RequestMappingInfo)
    • 遍历所有的bean,获取类上是否有@Controller@RequestMapping注解的bean
    • 再遍历所有的方法,筛选方法上是否有@RequestMapping注解
    • 最后注册成两个map存起来,以后映射方法从这里获取
      • MappingRegistry#MultiValueMap<String, T> pathLookup
        • key为@RequestMapping注解的映射路径
        • value为RequestMappingInfo对象
      • MappingRegistry#Map<T, MappingRegistration> registry
        • key为RequestMappingInfo对象
        • value为MappingRegistration对象(包含Controller#Method)
  • 解析@ControllerAdvice注解
    • 遍历所有的bean,筛选类上@ControllerAdvice注解的bean
      • 如果bean实现接口RequestBodyAdviceResponseBodyAdvice,那就是请求响应数据增强器
      • 如果bean有方法存在@ExceptionHandler,那就是异常处理器

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!