// ContextLoaderListener用于在Servlet容器启动时,创建一个全局可发现的ApplicationContext
// ContextLoaderListener继承自ContextLoader,创建ApplicationContext并发布到全局(保存为ServletContext的属性)就是全由该父类实现的
// 为了能在Servlet容器启动时执行程序,所以ContextLoaderListener实现了ServletContextListener接口
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
}
// 负责创建一个ApplicationContext
public class ContextLoader {
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(...);
}
long startTime = System.currentTimeMillis();
if (this.context == null) {
// 先通过determineContextClass(...)获取ApplicationContext的具体实现类,然后通过该类创建实例
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
// loadParentContext(...)默认返回null,可由子类重写(实际应用中并没有重写)
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
// 配置和刷新上下文
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 将创建的上下文保存在ServletContext中,这样Web应用的其他地方就可以通过ServletContext获取此上下文
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
} else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
return this.context;
}
// 决定ApplicationContext的具体实现类
protected Class<?> determineContextClass(ServletContext servletContext) {
// 获取ServletContext中key为"contextClass"的参数作为ApplicationContext的具体实现类
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
} else {
// defaultStrategies是spring-web包下org/springframework/web/context/ContextLoader.properties文件加载而成的Properties(该类的静态块中完成了这一加载过程)
// org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
// 所以ApplicationContext的具体实现类为XmlWebApplicationContext
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
}
// 配置和刷新上下文
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
// AbstractApplicationContext的id属性默认是ObjectUtils.identityToString(this)
// 如果id还是默认id,那么就重新设置id
// 先通过ServletContext中key为"contextConfigLocation"的参数值来设置id
// 如果ServletContext中不包含该key,就用org.springframework.web.context.WebApplicationContext:ServletContext的路径
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
if (idParam != null) {
wac.setId(idParam);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
// 将ServletContext保存在ApplicationContext中,便于后面使用
wac.setServletContext(sc);
// 获取ServletContext中key为"contextConfigLocation"的参数用来作为配置的XML的路径
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
// 默认是StandardServletEnvironment
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
// 在refresh()之前执行ApplicationContextInitializer.initialize(...),通常用于对ApplicationContext进行自定义的初始化
customizeContext(sc, wac);
// 刷新ApplicationContext
wac.refresh();
}
// 执行所有注册的ApplicationContextInitializer的initialize(...)方法
protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
// 决定有哪些类型的Class
List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses = determineContextInitializerClasses(sc);
// 将已确定的ApplicationContextInitializer类实例化并进行注册
for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
// 获取ApplicationContextInitializer的类型参数T所代表的Class
Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
throw new ApplicationContextException(...);
}
this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
}
// 对所有已注册的ApplicationContextInitializer进行排序,然后依次调用其initialize(...)方法
AnnotationAwareOrderComparator.sort(this.contextInitializers);
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
initializer.initialize(wac);
}
}
// 决定哪些ApplicationContextInitializer需要被注册
protected List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>
determineContextInitializerClasses(ServletContext servletContext) {
// 用于保存所有注册的ApplicationContextInitializer类型
List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> classes = new ArrayList<>();
// ServletContext中key为"globalInitializerClasses"的参数所配置的ApplicationContextInitializer的子类全名
// 多个类全名用','、';'或'\t\n'分割
String globalClassNames = servletContext.getInitParameter(GLOBAL_INITIALIZER_CLASSES_PARAM);
if (globalClassNames != null) {
for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
// loadInitializerClass(...)根据类全名加载出Class对象,这必须是ApplicationContextInitializer的子类
classes.add(loadInitializerClass(className));
}
}
// ServletContext中key为"contextInitializerClasses"的参数所配置的ApplicationContextInitializer的子类全名
// 多个类全名用','、';'或'\t\n'分割
String localClassNames = servletContext.getInitParameter(CONTEXT_INITIALIZER_CLASSES_PARAM);
if (localClassNames != null) {
for (String className : StringUtils.tokenizeToStringArray(localClassNames, INIT_PARAM_DELIMITERS)) {
classes.add(loadInitializerClass(className));
}
}
return classes;
}
}
DispatcherServlet(WEB功能) -> FrameworkServlet(容器功能) -> HttpServletBean(配置功能) -> HttpServlet -> GenericServlet -> Servlet
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
// Servlet初始化入口
public final void init() throws ServletException {
// 将Servlet配置的所有InitParameter封装成PropertyValues,requiredProperties(一个字符串集合)中所有的key必须有相应的InitParameter
// 将当前Servlet对象(实际上是DispatcherServlet对象)中的属性用pvs进行设置,也就是用InitParameter来设置DispatcherServlet的属性
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
// 初始化ApplicationContext与Servlet
initServletBean();
}
}
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected final void initServletBean() throws ServletException {
long startTime = System.currentTimeMillis();
// 初始化WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
// 默认为空方法,供子类扩展,实际上到DispatcherServlet也没有扩展该方法
initFrameworkServlet();
}
protected WebApplicationContext initWebApplicationContext() {
// 从ServletContext中获取ApplicationContext(ContextLoaderListener在ServletContext中设置了ApplicationContext)
// 实际上调用servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 如果当前Servlet关联的webApplicationContext不为空,那么设置其双亲ApplicationContext并对其进行配置和刷新
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// 实际上调用servletContext.getAttribute(attributName)获取ApplicationContext
// attributeName由FrameworkServlet.contextAttribute属性提供(默认为null)
wac = findWebApplicationContext();
}
// 通常DispatcherServlet在启动时会进入此分支,在此处创建ApplicationContext
if (wac == null) {
// 创建ApplicationContext并以rootContext作为父ApplicationContext
wac = createWebApplicationContext(rootContext);
}
// onRefresh(...)在DispatcherServlet中实现,负责完成Spring的Web功能的初始化
// this.refreshEventReceived表示是否已经完成了Spring的Web功能的初始化
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
// this.publishContext默认为true,将ApplicationContext发布,以便其他地方可以通过ServletContext来获取该ApplicationContext
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
// 创建WebApplicationContext
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
// 获取需要实例化的ApplicationContext类型并用之进行实例化
// 默认ApplicationContext类型为FrameworkServlet.DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class
Class<?> contextClass = getContextClass();
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
// 设置WebApplicationContext的XML配置文件的位置,其值来自contextConfigLocation属性,属性可以通过Servlet配置的InitParameter配置
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
// 配置和刷新上下文
configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
// 设置ApplicationContext的id,与ContextLoader的configureAndRefreshWebApplicationContext方法类似
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
if (this.contextId != null) {
wac.setId(this.contextId);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
// 注册一个ApplicationListener,在后面调用wac.refresh()时会发布监听事件,那时会回调SourceFilteringListener.onApplicationEvent(...)方法
// SourceFilteringListener.onApplicationEvent(...)直接调用了第二个构造参数(即ContextRefreshListener)的onApplicationEvent(...)方法
// ContextRefreshListener.onApplicationEvent(...)直接调用了Servlet实现类的onRefresh(...)方法
// DispatcherServlet的onRefresh(...)方法完成了Spring的Web功能的初始化
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// 默认是StandardServletEnvironment
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
// 默认为空函数,提供给子类扩展(实际上到DispatcherServlet也没有进行扩展)
postProcessWebApplicationContext(wac);
// 在refresh()之前执行ApplicationContextInitializer.initialize(...),通常用于对ApplicationContext进行自定义的初始化
// 与ContextLoader的customizeContext(...)方法类似
applyInitializers(wac);
// 刷新上下文
wac.refresh();
}
// 执行所有注册的ApplicationContextInitializer的initialize(...)方法
protected void applyInitializers(ConfigurableApplicationContext wac) {
// ServletContext中key为"globalInitializerClasses"的参数所配置的ApplicationContextInitializer的子类全名
// 多个类全名用','、';'或'\t\n'分割
String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);
if (globalClassNames != null) {
for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
// loadInitializer(...)根据类全名进行实例化
this.contextInitializers.add(loadInitializer(className, wac));
}
}
// contextInitializerClasses成员变量所代表的ApplicationContextInitializer的子类全名,属性可以通过Servlet配置的InitParameter配置
// 多个类全名用','、';'或'\t\n'分割
if (this.contextInitializerClasses != null) {
for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {
this.contextInitializers.add(loadInitializer(className, wac));
}
}
// 对所有已注册的ApplicationContextInitializer进行排序,然后依次调用其initialize(...)方法
AnnotationAwareOrderComparator.sort(this.contextInitializers);
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
initializer.initialize(wac);
}
}
}
// 该类主要完成了Spring的Web功能
public class DispatcherServlet extends FrameworkServlet {
// Spring的Web功能的初始化
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
// 初始化spirng-mvc九大组件
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
SpringMVC大九组件的初始化,基本都使用了相同的套路,除了文件上传组件默认为null以外,其他组件最终都通过DispatcherServlet.getDefaultStrategies(…)来获取默认值(通过spring-webmvc包下org/springframework/web/servlet目录中的DispatcherServlet.properties来进行配置,不同Spring版本可以通过该配置来进行组件功能的扩展)。可以通过向AppicationContext中注册bean的方式来覆盖默认组件。
public class DispatcherServlet extends FrameworkServlet {
// 其实就是调用getDefaultStrategies(...)方法,但是将列表转换为单个元素的对象,也就是说列表必须有且仅有一个元素
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
List<T> strategies = getDefaultStrategies(context, strategyInterface);
if (strategies.size() != 1) {
throw new BeanInitializationException(...);
}
return strategies.get(0);
}
// 获取spring-webmvc包下org/springframework/web/servlet目录中DispatcherServlet.properties属性文件中,
// key为strategyInterface全类名对应的value(value为strategyInterface的实现类的全类名,多个全类名用','分割)实例化后的列表
// 如果DispatcherServlet.properties中没有对应的key,那么返回一个空列表
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
// Properties对象defaultStrategies会在类的静态块中初始化,
// 由spring-webmvc包下org/springframework/web/servlet目录中的DispatcherServlet.properties文件加载而来
// 如该文件中保存了如下key-value
// org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
// org.springframework.web.servlet.HandlerMapping=org...BeanNameUrlHandlerMapping,org...RequestMappingHandlerMapping
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value == null) {
// 如果没有配置相应strategyInterface的实现类,返回空列表
return new LinkedList<>();
} else {
// 将','分割的多个类全名解析为数组格式
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
// 将配置的类实例化后放入列表并返回
for (String className : classNames) {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
// 根据clazz构建一个原型模式的RootBeanDefinition
// 并调用ApplicationContext中BeanFactory的createBean(...)方法创建对象,该过程会执行创建Bean的扩展(包括属性注入等)
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
return strategies;
}
}
}
该组件用来将上传文件的请求对象转换为MultipartHttpServletRequest类型,从而实现文件上传功能,默认情况下未注册该组件。可以向容器注册一个名为"multipartResolver"的bean来进行该组件的注册。
spring-mvc中提供的实现类有:
public interface MultipartResolver {
// 判断请求是否是文件上传请求(通常是判断请求的ContextType是否是以"multipart/"开头)
boolean isMultipart(HttpServletRequest request);
// 将文件上传的请求封装成MultipartHttpServletRequest,该类型的请求提供了许多关于获取上传的文件的接口
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException;
// 完成文件上传后的清理工作
void cleanupMultipart(MultipartHttpServletRequest request);
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取名为"multipartResolver"的Bean作为Web应用的MultipartResolver,默认为null
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
} catch (NoSuchBeanDefinitionException ex) {
this.multipartResolver = null;
}
}
}
该组件主要用于国际化功能,通过解析请求得到Locale对象,默认使用AcceptHeaderLocaleResolver(这与spring-mvc的版本有关,后面的默认值也与版本有关,以下不再说明)。可以向容器注册一个名为"localeResolver"的bean来覆盖默认组件。
spring-mvc中提供的实现类有:
public interface LocaleResolver {
// 解析请求得到Locale对象
Locale resolveLocale(HttpServletRequest request);
void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale);
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取名为"localeResolver"的Bean作为Web应用的LocaleResolver
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
} catch (NoSuchBeanDefinitionException ex) {
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
}
}
}
该组件主要用于主题功能,通过解析请求得到主题名,默认使用FixedThemeResolver。可以向容器注册一个名为"themeResolver"的bean来覆盖默认组件。
spring-mvc中提供的实现类有:
public interface ThemeResolver {
// 解析请求得到主题名
String resolveThemeName(HttpServletRequest request);
void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取名为"themeResolver"的Bean作为Web应用的ThemeResolver
private void initThemeResolver(ApplicationContext context) {
try {
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
} catch (NoSuchBeanDefinitionException ex) {
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
}
}
}
该组件会根据请求(一般是请求的url)来获取匹配的拦截器和对请求进行处理的对象(该对象如何处理请求是由HandlerAdapter决定的),默认使用了BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctionMapping。可以向容器注册一个或多个HandlerMapping实现类的bean来覆盖默认组件。当客户端发起请求时,会依次调用这些HandlerMapping的getHandler(…)方法,直到获取HandlerExecutionChain为止。
spring-mvc中提供的实现类有:
public interface HandlerMapping {
// 根据请求获取执行链(可以包括多个拦截器,必须包含一个Handler)
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取所有HandlerMapping实现类或名为"handlerMapping"的Bean作为Web应用的List
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// this.detectAllHandlerMappings默认为true
if (this.detectAllHandlerMappings) {
// 从ApplicationContext中获取所有HandlerMapping实现类的Bean,排序后作为Web应用的List
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
// 从ApplicationContext中获取名为"handlerMapping"的Bean作为Web应用的List
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException ex) {
// 什么也不做
}
}
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
}
}
几乎所有的HandlerMapping都继承了AbstractHandlerMapping,而AbstractHandlerMapping实现了ApplicationContextAware接口,所以setApplicationContext(…)方法是初始化的入口。
更详细的继承关系:AbstractHandlerMapping -> WebApplicationObjectSupport -> ApplicationObjectSupport
public abstract class ApplicationObjectSupport implements ApplicationContextAware {
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) { // context通常不为null,所以不会进入该分支
this.applicationContext = null;
this.messageSourceAccessor = null;
} else if (this.applicationContext == null) { // 通常会进入此分支
// 判断ApplicationContext是不是期望的类型,如果不是抛出异常
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(...);
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
// 由子类实现初始化,实际在WebApplicationObjectSupport进行了实现
initApplicationContext(context);
} else { // 避免重复初始化
if (this.applicationContext != context) {
throw new ApplicationContextException(...);
}
}
}
}
public abstract class WebApplicationObjectSupport extends ApplicationObjectSupport {
protected void initApplicationContext(ApplicationContext context) {
// 调用父类ApplicationObjectSupport的initApplicationContext(context)
// 父类的方法却直接调用了initApplicationContext()方法,AbstractHandlerMapping实现了该方法
super.initApplicationContext(context);
// 如果是Web应用,初始化Servlet相关,个人觉得对于Handler的注册由子类实现initServletContext(...)方法比较恰当
// 然而该方法在springmvc默认都是空方法
if (this.servletContext == null && context instanceof WebApplicationContext) {
this.servletContext = ((WebApplicationContext) context).getServletContext();
if (this.servletContext != null) {
initServletContext(this.servletContext);
}
}
}
}
public abstract class AbstractHandlerMapping {
protected void initApplicationContext() throws BeansException {
// 实际上是个空方法,什么也没有干
extendInterceptors(this.interceptors);
// 将所有MappedInterceptor类型的Bean注册进adaptedInterceptors
detectMappedInterceptors(this.adaptedInterceptors);
// 将this.interceptors变量中的拦截器也注册进adaptedInterceptors
initInterceptors();
}
}
BeanNameUrlHandlerMapping继承了AbstractMethodMapping,实现了公用功能的初始化,而且重写了初始化过程中提供的扩展接口,从而实现Handler的初始化。
BeanNameUrlHandlerMapping -> AbstractDetectingUrlHandlerMapping -> AbstractUrlHandlerMapping
public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping {
public void initApplicationContext() throws ApplicationContextException {
// 确保父类的功能能够实现(初始化拦截器)
super.initApplicationContext();
// 初始化Handler
detectHandlers();
}
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
// this.detectHandlersInAncestorContexts默认为false,所以不会获取祖先上下文中的beanName
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
// 根据beanName来决定url,由子类BeanNameUrlHandlerMapping实现
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// 分别将所有的url分别和相应的bean绑定
registerHandler(urls, beanName);
}
}
}
}
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
// 将beanName对应bean以"/"开头的ID和所有别名作为urls
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
}
RequestMappingHandlerMapping不但继承了AbstractMethodMapping,实现了公用功能的初始化,还通过实现InitializingBean接口,来完成Handler的初始化。
RequestMappingHandlerMapping -> RequestMappingInfoHandlerMapping -> AbstractHandlerMapping
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
// UrlPathHelper主要用于对url的编解码,从请求中获取url等
this.config.setUrlPathHelper(getUrlPathHelper());
// 用于请求的匹配,获取url路径中的参数等(如/ab/{param}中的param)
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(useSuffixPatternMatch());
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
this.config.setContentNegotiationManager(getContentNegotiationManager());
// 该方法在AbstractHandlerMethodMapping中实现,用于完成handler的注册
super.afterPropertiesSet();
}
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 获取方法的@RequestMapping注解,会根据@RequestMapping注解的各种属性来初始化RequestMappingInfo
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 获取类上的@RequestMapping注解
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 将两个注解进行合并
info = typeInfo.combine(info);
}
// 添加默认的前缀
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
// 初始化跨域
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
Class<?> beanType = handlerMethod.getBeanType();
CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class);
CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
// 如果类与方法都未被CrossOrigin注解标记,那么就不支持跨域请求
if (typeAnnotation == null && methodAnnotation == null) {
return null;
}
// 用类上的CrossOrigin注解更新配置,再用方法上的CrossOrigin注解更新配置(聚集类型会合并)
CorsConfiguration config = new CorsConfiguration();
updateCorsConfig(config, typeAnnotation);
updateCorsConfig(config, methodAnnotation);
// 如果config的allowedMethod为空,那么用mapping支持的请求方法更新它
if (CollectionUtils.isEmpty(config.getAllowedMethods())) {
for (RequestMethod allowedMethod : mappingInfo.getMethodsCondition().getMethods()) {
config.addAllowedMethod(allowedMethod.name());
}
}
// 配置默认值
return config.applyPermitDefaultValues();
}
}
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
// 只是作为回调的钩子,具体工作转交给initHandlerMethods()来完成
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
// getCandidateBeanNames()用于获取ApplicationContext中注册的所有bean的ID
// this.detectHandlerMethodsInAncestorContexts决定是否包含组件ApplicationContext中注册的bean,默认为false,即不包括
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 注册Handler,实际上Handler是一个方法
processCandidateBean(beanName);
}
}
// 在handler注册后处理,由子类实现,实际上只是打印了一些日志,没有做其他有意义的事
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
Class<?> beanType = obtainApplicationContext().getType(beanName);
// 根据类(或其父类,以及代理的原始类)是否被@Controller或@RequestMapping(或被其标记的注解)标记来判断当前bean是否是一个Controller
// 只有Controller的方法才有可能成为Handler
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
protected void detectHandlerMethods(Object handler) {
// 如果是String类型,那么表示beanName,通过ApplicationContext来获取bean的类型
// 如果不是String类型,直接获取其类型
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
// 如果是使用代理类,那么这里获取原始类型
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取Method及其配置(RequestMapping配置)的映射,这里的T代表RequestMappingInfo类型(包含了映射配置、与url匹配方式等)
// 请求到来时会根据请求的url,由匹配方式匹配到相应的映射配置,然后根据映射配置找到相应的Method(即Handler)
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
return getMappingForMethod(method, userType);
});
methods.forEach((method, mapping) -> {
// 将方法转换为AOP代理的方法
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 直接委托给Mapping注册中心进行注册,注册中心为内部类MappingRegistry的一个实例
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
class MappingRegistry {
public void register(T mapping, Object handler, Method method) {
// Kotlin语言,忽略
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
...
}
this.readWriteLock.writeLock().lock();
try {
// 将handler与method封装为最终的Handler,对于RequestMappingHandlerMapping,最终的Handler是个HandlerMethod类型
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// 验证handlerMethod,主要避免重复注册
validateMethodMapping(handlerMethod, mapping);
// 注册RequestMappingInfo与Handler的关系,一个RequestMappingInfo可能包含多个url
this.mappingLookup.put(mapping, handlerMethod);
// url包含直接的url和正则的url,正则的url需要费时解析,而普通的url只需要字符串比较即可,所以单独处理直接url以提高匹配效率
// 缓存直接url(如果是正则url则不缓存,如果是多个url,那么每一个单独缓存)
// 直接url只需要简单的字符串比较而无需正则匹配,这样可以快速找到mapping(RequestMappingInfo)
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
// mapping名
String name = null;
if (getNamingStrategy() != null) {
// 默认使用Controller的简单类名,各个单词的首字母大写 + "#" + 方法名
// 如com.test.MyController的test()方法,那么名就是MC#test()
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
// 获取跨域配置,initCorsConfiguration(...)在RequestMappingHandlerMapping中实现了
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
// 注册handler与该handler对应的跨域配置
this.corsLookup.put(handlerMethod, corsConfig);
}
// 注册mapping与MappingRegistration的关系
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
} finally {
this.readWriteLock.writeLock().unlock();
}
}
}
}
public final class MethodIntrospector {
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<>();
// 初始化后会包含目标类及其实现的所有接口(包括其祖先类实现的所有接口),如果类是代理,还会包含被代理的原始类
Set<Class<?>> handlerTypes = new LinkedHashSet<>();
Class<?> specificHandlerType = null;
// 如果是代理类(这里就是指Controller的代理类),那么获取原始类(即Controller本身)并注册
if (!Proxy.isProxyClass(targetType)) {
specificHandlerType = ClassUtils.getUserClass(targetType);
handlerTypes.add(specificHandlerType);
}
// 注册目标类及其实现的所有接口(包括其祖先类实现的所有接口)
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
// 扫描目标类、原始类、及其实现的所有接口中定义的所有方法(私有方法等会被扫描)
for (Class<?> currentHandlerType : handlerTypes) {
// 被代理的原始类
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
// 第一个参数是目标类、第二个参数用于注册回调、第三个参数用于过滤回调(默认过滤掉桥方法与合成方法,且不包含父类中定义的方法)
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
// 如果是特殊方法(如接口的方法等),将其转换为目标类的方法
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// metadataLookup是传入的一个lambda表达式,其实就是简单地回调了RequestMappingHandlerMapping.getMappingForMethod(...)
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
// 从此处可见,当前class定义的方法(无论是私有、保护还是公有的方法都能被注册)
Method[] methods = getDeclaredMethods(clazz, false);
for (Method method : methods) {
// 过滤掉桥方法与合成方法
if (mf != null && !mf.matches(method)) continue;
// 回调进行方法注册
mc.doWith(method);
}
// 因为传入的mf是USER_DECLARED_METHODS,所以不会扫描父类中定义的方法
if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
// 处理父类中定义的方法,会递归所有祖先类
doWithMethods(clazz.getSuperclass(), mc, mf);
} else if (clazz.isInterface()) {
// 因为不会进入上一个分支,所以会处理接口继承的接口方法
// 如果进入了上一个分支,说明目标类及其祖先类的方法都被处理了,那么所有接口的方法肯定也被处理了(接口的任一方法肯定被某一类实现了)
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
}
// 几乎所有的HandlerMapping都继承自该类
public abstract class AbstractHandlerMapping {
// 这是一个模板方法,子类根据自己的需求重写部分接口
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据请求如url,获取handler
Object handler = getHandlerInternal(request);
if (handler == null) {
// 找不到匹配的handler时的默认handler,它初始化为空,需要设置默认handler才能获得
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// 如果handler是String类型的,那么handler实际上是handler注册的beanName
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 获取处理链,包括一个handler与一系列的拦截器
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// hasCorsConfigurationSource(...)根据handler是否实现了CorsConfigurationSource接口来判断是否支持跨域
// RequestMethodHandleMapping的handler是HandlerMethod类,不可能实现了CorsConfigurationSource接口
// BeanNameUrlHandlerMapping的handler是Controller类,看程序员是否实现了CorsConfigurationSource接口
// CorsUtils.isPreFlightRequest(...)根据请求信息来判断是否支持跨域
// 请求必须包含请求头Origin和Access-Control-Request-Method,且必须是OPTIONS类型请求,那么就是跨域
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
// 如果handler实现了CorsConfigurationSource接口,通过其getCorsConfiguration(...)方法获取CorsConfiguration
// RequestMethodHandleMapping重写了该方法,先调用父类的该方法,如果无法获取CorsConfiguration,再搜索初始化时注册的
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
// 将两个CorsConfiguration属性进行合并
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
// 在拦截器链开头添加一个拦截器,该拦截器会根据配置设置响应response的响应头
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 如果传入的handler已经是HandlerExecutionChain,那么我们它已经包含了handler,无需在处理
// 否则我们就新建一个HandlerExecutionChain并用handler进行初始化
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 从请求中获取相对url
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// MappedInterceptor类型的拦截器需要匹配url才会起到拦截作用,其他类型的拦截器拦截所有请求
// 通过 配置的拦截器会被解析为MappedInterceptor拦截器
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
}
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 从请求中获取相对url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
// 寻找handler
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
// 如果路径只是一个"/",那么就优先用rootHandler来处理,rootHandler默认为null
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
// 否则用默认defaultHander来处理,默认defaultHandler也为null
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
// 验证和发布参数,如果进入了该分支,那么该HandlerMapping就有默认的Handler,那么后面的HandlerMapping是无法作用的
if (rawHandler != null) {
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// 从handlerMap中根据key(相对url)获取Handler
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// 如果是String类型,说明得到的是beanName,通过AppicationContext来获取Bean作为handler
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 验证作用,实际上是个空函数
validateHandler(handler, request);
// 发布一些参数
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// 无法直接匹配,采取正则匹配,matchingPatterns保存匹配上的正则格式的url
List<String> matchingPatterns = new ArrayList<>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
} else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
}
// 取最小的一个作为最佳匹配的正则url
String bestMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
matchingPatterns.sort(patternComparator);
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
// 根据正则url查找到相应的handler
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(...);
}
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
// 获取匹配"*"和"?"的段(段就是路径中用"/"隔开的一段段内容)
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
// 用于保存正则url中匹配的参数及其值
Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
// 发布一些参数
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}
return null;
}
// 用于发布一些请求相关的参数
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) {
// 以rawHanlder作为handler创建一个HandlerExecutionChain,以便注册默认拦截器
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
// 主要将最佳匹配的路径(如/api/goods/{id})和handler发布出去(request属性方式)
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
// 主要将路径中的参数值通过key-value发布到一个Map类型的request属性中
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
}
return chain;
}
}
public AbstractHandlerMethodMapping<RequestMappingInfo> extends AbstractHandlerMapping {
// 根据请求获取Handler
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 从请求中获取相对url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
// 根据url找到Handler
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// handlerMethod.createWithResolvedBean()确保用于调用Method的对象是期望的对象实例(Controller实例)
// 如果是String类型,那么以此为beanName从ApplicationContext中获取Bean来作为期望的对象实例
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} finally {
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
// Match包含一个mapping,一个Handler,也就是只要匹配了,就会生成一个Match保存于此(Match的mapping只对应一个url)
List<Match> matches = new ArrayList<>();
// 获取能够直接匹配的mapping(非正则url的RequestMappingInfo),这是url对应的原始mapping
// 如果该mapping初始化时包含了多个url,那么此时的mapping也包含多个url
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
// 如果找到直接匹配的mapping,那么获取
if (directPathMatches != null) {
// 将直接匹配的mapping进行遍历,找到对应的Handler,并且把原始mapping封装出一个新mapping(该mapping的url只有当前请求的url)
addMatchingMappings(directPathMatches, matches, request);
}
// 如果无法直接匹配,那么采取正则匹配(可见正则匹配的优先级低于直接匹配的优先级)
if (matches.isEmpty()) {
// 将所有注册的mapping进行遍历,根据正则匹配的mapping找到Handler并与封装出新的mapping,两者组合成Match
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
// 如果不止一个匹配,找到最小的Match(不能有两个及以上的最小Match)
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(...);
}
}
// 将handler发布出去
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
// 将url路径中的参数及其值以map的方式保存,并以request属性的方式发布
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
// 没有匹配handler时,其他方式获取handler,默认会返回null
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
}
该组件会根据对请求进行处理的对象来决定如何处理请求,默认使用了HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter、HandlerFunctionAdapter。可以向容器注册一个或多个HandlerAdapter实现类的bean来覆盖默认组件。
spring-mvc中提供的实现类有:
public interface HandlerAdapter {
// 当前HandlerAdapter是否可以处理指定的handler
boolean supports(Object handler);
// 执行handler的处理工作,得到ModelAndView
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 设置最后修改时间,一般都是直接设置为-1
long getLastModified(HttpServletRequest request, Object handler);
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取所有HandlerAdapter实现类或名为"handlerAdapter"的Bean作为Web应用的List
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
// this.detectAllHandlerAdapters默认为true
if (this.detectAllHandlerAdapters) {
// 从ApplicationContext中获取所有HandlerAdapter实现类的Bean,排序后作为Web应用的List
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
} else {
try {
// 从ApplicationContext中获取名为"handlerAdapter"的Bean作为Web应用的List
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
} catch (NoSuchBeanDefinitionException ex) {
...
}
}
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
}
}
}
该HandlerAdapter不需要初始化。
与RequestMappingHandlerMapping一样,RequestMappingHandlerAdapter同时实现了ApplicationContextAware与InitializingBean接口,其ApplicationContextAware接口的实现方式以及成绩结构与RequestMappingHandlerMapping完全相同,这里主要介绍InitializingBean方式的初始化。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
public void afterPropertiesSet() {
// 用于初始化被ControllerAdvice修饰的Bean
initControllerAdviceCache();
// XxxComposite表示的是一个聚合类的封装,并暴露和聚合类中单个元素相同的操作
// 注册默认的参数处理器,用于给handler以及modelAttribute方法提供参数来源
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 注册默认的initBinder方法处理器,用于给initBinder方法提供参数来源
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 注册默认的返回值转换器,用于处理handler的返回值
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
// 获取所有被ControllerAdvice修饰的Bean实例(已经对这些Bean进行了排序)
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);
}
// 将被@ModeAttribute修饰的方法缓存起来(即全局的ModeAttribute方法)
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
}
// 将被@InitBinder修饰的方法缓存起来(即全局的InitBinder方法)
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(adviceBean, binderMethods);
}
// 如果是RequestBodyAdvice或者ResponseBodyAdvice的子类,将其缓存下来
if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
}
}
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return ((Controller) handler).handleRequest(request, response);
}
}
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
public final boolean supports(Object handler) {
// 子类实现的supportsInternal(...)直接返回true
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return handleInternal(request, response, (HandlerMethod) handler);
}
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
// 直接返回true
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) {
ModelAndView mav;
// 检查请求,检查不通过会抛出异常,主要用于检查请求方法是否被支持(如GET、POST等)
checkRequest(request);
// 这一段就是为了执行 mav = invokeHandlerMethod(request, response, handlerMethod)这一行代码
// 如果要让同一个用户的所有请求序列化执行,需要对同一个Session加锁(在同一个session的请求释放前,该session的访问需要排队等候)
// 同一个用户请求的序列化访问会降低系统的吞吐量,默认是不需要加锁的
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
//
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
prepareResponse(response);
}
}
return mav;
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) {
// 封装了请求和响应
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// WebDataBinderFactory包含了全局与局部的BinderMethod
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// ModelFactory包含了BinderFactory、SessionAttributesHandler、全局与局部的ModeAttributeMethod
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// invocableMethod包含执行的方法、BindFactory、以及参数及返回值转换方式等
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
// 用来决定方法参数的发现名(如handler的形参应该与传入的哪个实参进行绑定)
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 创建一个ModeAndView容器,该容器可以保存构建ModeAndView的一些信息
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 将FlashMap方式重定向来的参数添加到Model容器
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 主要是从session中获取SessionAttribute,以及执行Model方法来获取键值对,从而初始化Model
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 异步请求相关设置
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
... 更多异步请求设置 ...
// 真正地执行handler方法,包括方法参数获取等
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// 如果开启了异步请求,那么这里直接返回,也无需渲染视图,直接交回给Servlet容器释放线程
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 构建ModelAndView对象
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
// 请求处理结
webRequest.requestCompleted();
}
}
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
// 得到的handlerType就是Controller的类型
Class<?> handlerType = handlerMethod.getBeanType();
// 根据Controller类型获取其局部BinderMethod
Set<Method> methods = this.initBinderCache.get(handlerType);
if (methods == null) {
// INIT_BINDER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
// MethodIntrospector.selectMethods(...)用于筛选出类中符合条件的方法,这里就是筛选出被@InitBinder注解的方法
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
// 缓存Controller与其局部BinderMethod的对应关系
this.initBinderCache.put(handlerType, methods);
}
// 用于保存此次请求,全局与局部的所有BinderMethod
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
// 向本次请求注册符合条件的全局BinderMethod
this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
// 判断handlerType是否是配置类的子类或者被配置的注解标记,或者位于配置的包及其子包下,这些配置在@ControllerAdvice中配置
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
for (Method method : methodSet) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
});
// 向本次请求注册局部BinderMethod
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
// 用全局与局部的BinderMethod构建WebDataBinderFactory
return createDataBinderFactory(initBinderMethods);
}
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
// 解析handler类(即Controller)的SessionAttributes注解,并将解析结果封装为SessionAttributesHandler对象
// 将handler类与SessionAttributesHandler以key-value形式进行了缓存
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
// 得到的handlerType就是Controller的类型
Class<?> handlerType = handlerMethod.getBeanType();
// 根据Controller类型获取其局部ModelAttributeMethod,先从缓存中取,取不到再解析然后缓存
Set<Method> methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
// 筛选出handlerType类中被@ModelAttribute标记,且未被@RequestMapping标记的方法
methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
// 缓存Controller与其局部ModeAttributeMethod的对应关系
this.modelAttributeCache.put(handlerType, methods);
}
// 用于保存此次请求,全局与局部的所有ModeAttributeMethod
List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
// 向本次请求注册符合条件的全局ModeAttributeMethod
this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
// 判断handlerType是否是配置类的子类或者被配置的注解标记,或者位于配置的包及其子包下,这些配置在@ControllerAdvice中配置
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
for (Method method : methodSet) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
});
// 向本次请求注册局部ModeAttributeMethod
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
// 用BinderFactory、SessionAttributesHandler、全局与局部的ModeAttributeMethod构建ModelFactory
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) {
// 将符合@SessionAttribute注解标识的Model属性放入session中
modelFactory.updateModel(webRequest, mavContainer);
// 如果请求已经处理完成,不需要ModelAndView就直接返回null,比如用@RequestBody标识的方法
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
// 如果需要重定向,将重定向参数暂存如FlashAttributes
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
}
public final class ModelFactory {
public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod) {
// 从session中获取model并放入容器
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
container.mergeAttributes(sessionAttributes);
// 执行Model方法并将返回值放入Model中
invokeModelAttributeMethods(request, container);
// 确保用@ModelAttribute标记且能被sessionAttributes支持的参数存在与容器中
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!container.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
}
container.addAttribute(name, value);
}
}
}
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container) {
while (!this.modelMethods.isEmpty()) {
// 与while一起使用模拟迭代操作
InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
if (container.containsAttribute(ann.name())) {
if (!ann.binding()) {
container.setBindingDisabled(ann.name());
}
continue;
}
// 执行model方法,如果返回值不为void类型,那么将返回值加入Model中
Object returnValue = modelMethod.invokeForRequest(request, container);
if (!modelMethod.isVoid()){
// 根据ModelAttribute注解的value值,与返回值类型来确定key
String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
if (!ann.binding()) {
container.setBindingDisabled(returnValueName);
}
// 将Model数据加入容器
if (!container.containsAttribute(returnValueName)) {
container.addAttribute(returnValueName, returnValue);
}
}
}
}
}
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 先通过getMethodArgumentValues(request, mavContainer, providedArgs)获取实参列表
// 再通过反射调用HandlerMethod方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
// 还未处理完请求,未处理完的请求才会进入ModelAndView的处理
mavContainer.setRequestHandled(false);
// 依次遍历所有已注册的HandlerMethodReturnValueHandler(HandlerAdapter初始化时完成注册)
// 直到找到支持当前返回值的Resolver并调用其handleReturnValue(...)方法,找不到抛出异常
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
// 获取方法需要的实参,在父类InvocableHandlerMethod中定义的
// providedArgs提供了一系列候选实参,优先从中挑选实参
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法的形参列表
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
// 如果不须要参数,那么返回空数组
return EMPTY_ARGS;
}
// args用于保存实参,和形参个数相同
Object[] args = new Object[parameters.length];
// 依次获取各个实参
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 如果提供的候选实参中有当前形参类型的子类,那么就用该候选实参作为当前形参的实参
// 因为一般候选实参是个空数组,也就是没有候选实参,所以这里无法获取到实参
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 依次遍历所有已注册的HandlerMethodArgumentResolver(HandlerAdapter初始化时完成注册)
// 直到找到支持当前形参的Resolver并调用其resolveArgument(...)方法,找不到抛出异常
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(...);
}
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
return args;
}
}
该组件用来解决请求处理过程中抛出的异常,默认使用了ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver。可以向容器注册一个或多个HandlerExceptionResolver实现类的bean来覆盖默认组件。
spring-mvc中提供的实现类有:
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取所有HandlerExceptionResolver实现类或名为"handlerExceptionResolver"的Bean作为Web应用的List
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
// this.detectAllHandlerExceptionResolvers默认为true
if (this.detectAllHandlerExceptionResolvers) {
// 从ApplicationContext中获取所有HandlerExceptionResolver实现类的Bean,排序后作为Web应用的List
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
} else {
try {
// 从ApplicationContext中获取名为"handlerExceptionResolver"的Bean作为Web应用的List
HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
} catch (NoSuchBeanDefinitionException ex) {
...
}
}
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
}
}
}
ExceptionHandlerExceptionResolver同时实现了ApplicationContextAware与InitializingBean接口,在setApplicationContext(…)只是完成了applicationContext的注入功能,具体的初始化过程发生在afterPropertiesSet()中。
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
implements ApplicationContextAware, InitializingBean {
public void afterPropertiesSet() {
// Do this first, it may add ResponseBodyAdvice beans
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);
}
}
private void initExceptionHandlerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
// 获取所有被@ControllerAdvice注解的Bean
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
for (ControllerAdviceBean adviceBean : adviceBeans) {
Class<?> beanType = adviceBean.getBeanType();
if (beanType == null) {
throw new IllegalStateException(...);
}
// 筛选出所有被@ExceptionHandler注解的方法,并解析方法能够处理的异常,以能处理的异常为key,当前方法为value进行注册
// 这样就能在发生全局异常时,根据异常类型,找到相应的处理方法
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
if (resolver.hasExceptionMappings()) {
this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
}
if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
this.responseBodyAdvice.add(adviceBean);
}
}
}
protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
return resolvers;
}
protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
handlers.add(new ModelAttributeMethodProcessor(true));
return handlers;
}
}
public class ExceptionHandlerMethodResolver {
public ExceptionHandlerMethodResolver(Class<?> handlerType) {
// 筛选出所有被@ExceptionHandler注解的方法
for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
// 注册当前method能够处理的异常类型
for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
addExceptionMapping(exceptionType, method);
}
}
}
private List<Class<? extends Throwable>> detectExceptionMappings(Method method) {
List<Class<? extends Throwable>> result = new ArrayList<>();
// 将method上的ExceptionHandler注解的值(一个元素类型为Throwable的数组)放入result中
detectAnnotationExceptionMappings(method, result);
if (result.isEmpty()) {
// 如果ExceptionHandler注解没有指定处理哪一类型的异常,那么形参有什么类型的异常就处理什么类型的异常
for (Class<?> paramType : method.getParameterTypes()) {
if (Throwable.class.isAssignableFrom(paramType)) {
result.add((Class<? extends Throwable>) paramType);
}
}
}
// 如果既没有用ExceptionHandler注解指定处理的异常类型,也没有通过形参来指定异常类型,那么程序有误,抛出异常
if (result.isEmpty()) {
throw new IllegalStateException(...);
}
return result;
}
}
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
implements ApplicationContextAware, InitializingBean {
public Method resolveMethod(Exception exception) {
return resolveMethodByThrowable(exception);
}
public Method resolveMethodByThrowable(Throwable exception) {
Method method = resolveMethodByExceptionType(exception.getClass());
// 如果找不到当前异常处理的方法,那么就根据引起异常的异常来找处理的方法,依次递归下去
if (method == null) {
Throwable cause = exception.getCause();
if (cause != null) {
method = resolveMethodByExceptionType(cause.getClass());
}
}
return method;
}
public Method resolveMethodByExceptionType(Class<? extends Throwable> exceptionType) {
// 这里又使用了缓存
Method method = this.exceptionLookupCache.get(exceptionType);
if (method == null) {
// 获取异常对应的处理函数
method = getMappedMethod(exceptionType);
this.exceptionLookupCache.put(exceptionType, method);
}
return method;
}
private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
// 筛选出能够处理当前异常的所有key(即已注册的异常中,当前异常父类的异常)
List<Class<? extends Throwable>> matches = new ArrayList<>();
for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
if (mappedException.isAssignableFrom(exceptionType)) {
matches.add(mappedException);
}
}
// 如果找到了能处理当前异常的处理方法,先对其排序,然后取第一个(也就是优先级最高的)
// 根据当前异常到比较异常的继承深度排序,深度越小越靠前,如A->B->C,很明显B到A的深度比C到A的深度小
if (!matches.isEmpty()) {
matches.sort(new ExceptionDepthComparator(exceptionType));
return this.mappedMethods.get(matches.get(0));
} else {
return null;
}
}
}
该组件用来从请求中获取默认的viewName(如果ModeAndView已经有了view,那么该组件将不会起作用),默认使用DefaultRequestToViewNameTranslator。可以向容器注册一个名为"viewNameTranslator"的bean来覆盖默认组件。
spring-mvc中提供的实现类有:
public interface RequestToViewNameTranslator {
String getViewName(HttpServletRequest request) throws Exception;
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取名为"viewNameTranslator"的Bean作为Web应用的RequestToViewNameTranslator
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
this.viewNameTranslator = context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
} catch (NoSuchBeanDefinitionException ex) {
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
}
}
}
该组件用于将viewName转换为View对象,默认使用InternalResourceViewResolver。可以向容器注册一个或多个ViewResolver实现类的bean来覆盖默认组件。
spring-mvc中提供的实现类有:
public interface ViewResolver {
// view的render(...)方法进行响应的渲染,返回不同类型的View,其渲染方式也不一样
View resolveViewName(String viewName, Locale locale) throws Exception;
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取所有ViewResolver实现类或名为"viewResolver"的Bean作为Web应用的List
// 默认只有org.springframework.web.servlet.view.InternalResourceViewResolver
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
// this.detectAllViewResolvers默认为true
if (this.detectAllViewResolvers) {
// 从ApplicationContext中获取所有ViewResolver实现类的Bean,排序后作为Web应用的List
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
} else {
try {
// 从ApplicationContext中获取名为"viewResolver"的Bean作为Web应用的List
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
} catch (NoSuchBeanDefinitionException ex) {
...
}
}
if (this.viewResolvers == null) {
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
}
}
}
该组件用于解决重定向过程中的参数传递问题,默认使用SessionFlashMapManager。可以向容器注册一个名为"flashMapManager"的bean来覆盖默认组件。
spring-mvc中提供的实现类有:
public interface FlashMapManager {
FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}
public class DispatcherServlet extends FrameworkServlet {
// 从ApplicationContext中获取名为"flashMapManager"的Bean作为Web应用的FlashMapManager
private void initFlashMapManager(ApplicationContext context) {
try {
this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
} catch (NoSuchBeanDefinitionException ex) {
this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
}
}
}
DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet -> GenericServlet -> Servlet
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
// 当请求到达Servlet容器时,Servlet容器会根据请求的url找到匹配的且已在Servlet容器注册过的Servlet并调用其service(...)方法
// 对于SpringMVC,所有的url都被映射到DispatherServlet,而DispatherServlet起作用的service(...)在父类FrameworkServlet中实现
// 实际上所有请求都是直接调用了processRequest(...)方法(doOptions(...)除外)
protected void service(HttpServletRequest request, HttpServletResponse response) {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
// 因为Servlet中并没有定义PATCH方法(PATCH是对PUT的扩展,并不是HTTP协议规定的方法),所以无法交给HttpServlet处理
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
} else {
// 调用HttpServlet的service(...)方法,这部分属于JavaEE内容,实际上就是根据请求方法调用相应的doXxx(...)方法,如doGet(...)
// 而doXxx(...)方法在FrameworkServlet中进行了实现,几乎都是直接调用processRequest(...)方法(doOptions(...)除外)
super.service(request, response);
}
}
// 请求处理
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
// LocaleContextHolder包含一个ThreadLocal变量,用于为每个线程保存一个LocaleContext
// 通过LocaleContextHolder的静态方法getLocaleContext()可以很方便的获取到LocaleContext(LocaleContextHolder几乎都是静态方法,这样在任何地方都可以直接调用)
// LocaleContext只有一个方法就是getLocale(),通过它可以获取到Locale对象
// 如果在此代码之前设置了当前线程的LocaleContext(如Servlet编程的Filter中),那么在后面的代码该LocaleContext是无效的
// 创建并设置新的LocaleContext前,获取老的LocaleContext是为了后面代码的还原操作
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
// 根据请求,由this.localeResolver来完成LocaleContext的创建
LocaleContext localeContext = buildLocaleContext(request);
// 与LocaleContextHolder原理类似,只是ServletRequestAttributes提供了其他功能
// 通过ServletRequestAttributes可以获取HttpServletRequest、HttpSession以及在相应对象中保存的attribute
// SpringWeb的request与session作用范围就是基于该对象的
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
// 将新创建的LocaleContext与ServletRequestAttributes设置到当前线程(后面代码会在请求处理完成时设置回原值)
// 如果在请求处理的过程中新创建了线程(如业务逻辑service中),那么在新线程中无法通过该方法获取到Locale对象
initContextHolders(request, localeContext, requestAttributes);
// WebAsyncManager类似于Servlet编程中的AsyncContext,用于异步编程(类似Servlet3引入的异步编程),与@Async注解没有任何关系
// WebAsyncUtils会直接new一个WebAsyncManager并缓存在当前ServletRequest的attribute中
// 这样同一个请求范围内,通过WebAsyncUtils.getAsyncManager(...)都将获得同一个WebAsyncManager对象
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// 通过asyncManager执行的异步线程,在执行自定义代码前后会进行额外的回调处理,这里注册了RequestBindingInterceptor类型的回调处理
// RequestBindingInterceptor用于在执行自定义代码前后分别执行initContextHolders(...)与resetContextHolders(...)方法
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
try {
// 该方法完成最主要的逻辑,在子类DispatherServlet中进行了定义
doService(request, response);
} catch (Throwable ex) {
failureCause = ex;
throw ex;
} finally {
// 将当前线程的LocaleContext与RequestAttributes还原,这样在之后的操作(如Servlet编程的Filter中)获取的依然是原值
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
// 请求结束额外处理,如销毁request-scope的Bean,更新Session等
requestAttributes.requestCompleted();
}
// 发布一个ServletRequestHandledEvent事件,继承ApplicationListener的监听器可监听此事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
// 创建LocaleContext
protected LocaleContext buildLocaleContext(final HttpServletRequest request) {
// this.localeResolver在初始化过程中完成了注入
LocaleResolver lr = this.localeResolver;
if (lr instanceof LocaleContextResolver) {
return ((LocaleContextResolver) lr).resolveLocaleContext(request);
} else {
// LocaleContext是个函数式接口,所以这里用Lambda表达式来表示一个匿名内部类
return () -> (lr != null ? lr.resolveLocale(request) : request.getLocale());
}
}
// 处理跨域请求
protected void doOptions(HttpServletRequest request, HttpServletResponse response) {
if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
processRequest(request, response);
if (response.containsHeader("Allow")) {
return;
}
}
super.doOptions(request, new HttpServletResponseWrapper(response) {
@Override
public void setHeader(String name, String value) {
if ("Allow".equals(name)) {
value = (StringUtils.hasLength(value) ? value + ", " : "") + HttpMethod.PATCH.name();
}
super.setHeader(name, value);
}
});
}
}
public class DispatcherServlet extends FrameworkServlet {
protected void doService(HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 把一些常用的对象发布到请求域,以便在其他地方可以方便获取这些对象
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
if (this.flashMapManager != null) {
// 获取通过FlashMapManager重定向而来的参数,并将其保存在request中,同时将这些参数从FlashMapManager中清空(因为这些参数只在重定向中使用一次)
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
// 创建一个想要重定向时的空的参数持有者,供后面存放数据
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
// 将flashMapManager发布出去,让别的地方能够方便地获取到flashMapManager
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 如果是文件上传请求,就将请求封装为MultipartHttpServletRequest返回
processedRequest = checkMultipart(request);
// 是否是文件上传请求
multipartRequestParsed = (processedRequest != request);
// HandlerExecutionChain包含一个handler,以及一个HandlerInterceptor数组
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 在找不到处理方法的时候,直接向response里面写入404状态
noHandlerFound(processedRequest, response);
return;
}
// 获取可以处理handler的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 拦截器前处理,顺序调用HandlerInterceptor数组中每一个元素的preHandle(...)方法
// 如果某一个HandlerInterceptor的preHandle(...)返回false,那么不会继续往后调用并直接返回false
// 在上一步如果返回的是false,那么还会倒序调用所有HandlerInterceptor的afterCompletion(...)方法
// 如果拦截器链的调用最终返回false,就不会执行下面的控制器、视图等的处理了
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 通过适配器来调用处理方法,并将结果封装为ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 如果当前线程开启了异步,那么暂时不处理视图与后置处理,直接返回以便快速释放线程
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如果ModeAndView中没有view,那么通过viewNameTranslator从请求获取默认view
applyDefaultViewName(processedRequest, mv);
// 拦截器后处理,倒序调用HandlerInterceptor数组中每一个元素的postHandle(...)方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Throwable ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Throwableex) {
// 执行所有拦截器的afterCompletion(...)方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else {
// 如果不是异步且是文件上传请求,且已经处理,那么需要做清除工作
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
// 如果是文件上传请求,就将请求封装为MultipartHttpServletRequest返回
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {
logger.trace(...);
}
} else if (hasMultipartException(request)) {
logger.debug(...);
} else {
return this.multipartResolver.resolveMultipart(request);
}
}
return request;
}
// 遍历注册的所有HandlerMapping,直到找到HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
// 遍历注册的所有HandlerAdapter,直到某个HandlerAdapter的supports(...)方法返回true,表示HandlerAdapter能够处理handler
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException(...);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 如果前面的操作存在异常,那么首先进行异常处理
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 依次调用已注册的HandlerExceptionResolver,直到某个Resolver的返回不为null为止,如果最终返回null,说明所有注册的Resolver都无法处理该异常
mv = processHandlerException(request, response, handler, exception);
// 如果上一步返回的ModelAndView为null,表示异常未得到解决,ModelAndView也不是异常得到的ModelAndView
errorView = (mv != null);
}
}
if (mv != null && !mv.wasCleared()) {
// 通过view来渲染响应
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
if (mappedHandler != null) {
// 执行所有拦截器的afterCompletion(...)方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) {
Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
// 根据viewName得到view
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 遍历所有的ViewResolver,直到能将viewName转换为View为止
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException(...);
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException(...);
}
}
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 通过view来渲染响应
view.render(mv.getModelInternal(), request, response);
}
}