1、DispatcherServlet的初始化过程概述
DispatcherServlet是一个Servlet,也具有Servlet的生命周期:实例化(instance)->初始化(init)->调用service方法->销毁(destroy)。当应用启动的时候,会调用DispatcherServlet的初始化方法。本篇文章将浅析DispatcherServlet以及两个重要组件HandlerMapping和HandlerAdapter的初始化过程。

如图所示:
1、首先会从GenericServlet的init()方法开始,逐步执行到DispatcherServlet的父类FrameworkServlet的initServletBean()方法。
2、在initServletBean()方法中,会去创建IOC容器WebApplicationContext。
3、IOC容器会去创建组件,这一步中,重点关注RequestMappingHandlerMapping和RequestMappingHandlerAdapter的初始化。
4、容器创建完成之后,容器发布ContextRefreshedEvent事件。而FrameworkServlet的内部类ContextRefreshListener实现了ApplicationListener,监听到此事件之后,执行onRefresh()方法
5、DispatcherServlet重写了父类的onRefresh()方法,并在onRefresh()方法里面,执行初始化策略,从而初始化各个组件。
2、源码浅析
断点打到HttpServletBean的init()方法中。
2.1、DispatcherServlet祖传的init()方法
HttpServletBean的init()方法:
public final void init() throws ServletException {
// 省略其他代码
// 解析init-param并封装到pvs中。
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
//将当前的servlet类包装为BeanWrapper,从而注入init-param
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// 留给子类扩展
initServletBean();
//省略其他代码
}
HttpServletBean的子类FrameworkServlet的initServletBean()方法:
protected final void initServletBean() throws ServletException {
//省略其他代码
long startTime = System.currentTimeMillis();
try {
//初始化IOC容器WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
//留给子类实现
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
//省略其他代码
}
2.2、WebApplicationContext的初始化
接着上一步中FrameworkServlet的 initWebApplicationContext()方法:
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//省略其他代码
if (wac == null) {
// 创建一个WebApplicationContext容器
wac = createWebApplicationContext(rootContext);
}
//省略其他代码
return wac;
}
createWebApplicationContext()方法:
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
//省略其他代码
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
//设置环境和父容器
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
//初始化Spring环境包括加载配置文件等
configureAndRefreshWebApplicationContext(wac);
return wac;
}
configureAndRefreshWebApplicationContext(wac)方法:
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
//省略其他代码
// 加载配置文件然后刷新容器
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
}
2.3、RequestMappingHandlerMapping的初始化
RequestMappingHandlerMapping将会实例化,带有@Controller注解的类中@RequestMapping注解的方法。SpringMVC也是基于这个类,找到请求路径映射的类和方法。
RequestMappingHandlerMapping初始化过程如图所示:

因为这个类的爷爷类实现了InitializingBean接口,而他又重写了afterPropertiesSet()方法。因此在这个类初始化的时候,会调用afterPropertiesSet()方法。
断点打到RequestMappingHandlerMapping类中的afterPropertiesSet()方法。
afterPropertiesSet方法:
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
}
然后来到爷爷类的afterPropertiesSet方法:
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//这里的beanNames就是IOC容器中所有的组件名称
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
//判断这个类是否带有@Controller或@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
//检测这个类的方法
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
isHandler(beanType)方法:
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
detectHandlerMethods(beanName)方法,这里的Handler封装了类的信息,Method类封装了方法的信息,泛型T实际上是RequestMappingInfo,而RequestMappingInfo封装了@RequestMapping注解里面各个属性的值。
protected void detectHandlerMethods(final Object handler) {
//首先获取这个类的Class对象
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//查找这个类的所有方法,以及创建方法的RequestMappingInfo
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
//注册类、方法以及RequestMappingInfo信息
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
}
selectMethods()方法:
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
//用于返回的Map,key是方法对象,value是封装的RequestInfo对象
final Map<Method, T> methodMap = new LinkedHashMap<>();
Set<Class<?>> handlerTypes = new LinkedHashSet<>();
Class<?> specificHandlerType = null;
if (!Proxy.isProxyClass(targetType)) {
handlerTypes.add(targetType);
specificHandlerType = targetType;
}
handlerTypes.addAll(Arrays.asList(targetType.getInterfaces()));
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
//使用反射处理这个类的所有方法
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
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;
}
doWithMethods()方法:
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
Method[] methods = getDeclaredMethods(clazz);
//遍历这个类的所有方法
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
//执行的是上一步中lambda表达式中的方法
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null) {
//然后再递归调用父类的所有方法,这里直接进入Object类的所有方法。
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
mc.doWith(method);
method -> {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
//检查这个方法,调用的是detectHandlerMethods()里面的lambda表达式中的方法
//返回的是一个RequestMappingInfo对象
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
//将这个键值对放进map里面
methodMap.put(specificMethod, result);
}
}
}
metadataLookup.inspect(specificMethod);
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
getMappingForMethod(method, userType)方法:
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//首先创建这个方法的RequestMappingInfo对象
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//然后创建这个类的RequestMappingInfo对象
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//将这两个RequestMappingInfo对象合并为一个对象,拼接类和方法上的请求路径等等。
info = typeInfo.combine(info);
}
}
return info;
}
typeInfo.combine(info)方法
public RequestMappingInfo combine(RequestMappingInfo other) {
String name = combineNames(other);
PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition);
RequestMethodsRequestCondition methods = this.methodsCondition.combine(other.methodsCondition);
ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition);
HeadersRequestCondition headers = this.headersCondition.combine(other.headersCondition);
ConsumesRequestCondition consumes = this.consumesCondition.combine(other.consumesCondition);
ProducesRequestCondition produces = this.producesCondition.combine(other.producesCondition);
RequestConditionHolder custom = this.customConditionHolder.combine(other.customConditionHolder);
return new RequestMappingInfo(name, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}
重点来了,经过上面的步骤,已经将需要注册的类和方法放到Map<Method, T>中了。接下来,就是遍历这个Map,然后注册Method和RequestMappingInfo了。
在detectHandlerMethods()方法的最后:
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
然后进入registerHandlerMethod()方法:
public void register(T mapping, Object handler, Method method) {
//加上写锁
this.readWriteLock.writeLock().lock();
try {
//创建HandlerMethod对象
//HandlerMethod封装了类、方法、方法参数数组、这个类的beanFactory等信息。
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
//断言创建出来的HandlerMethod对象是唯一的
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//RequestMappingInfo作为键,handlerMethod作为值,放入mappingLookup中。
this.mappingLookup.put(mapping, handlerMethod);
//获取RequestMappingInfo的请求路径url
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
//将url作为键,RequestMappingInfo作为值,放入urlLookup中。
this.urlLookup.add(url, mapping);
}
//生成一个名字name
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
//把以上所有的信息,放进registry里面
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
DispatcherServlet拿到一个请求路径时,就是根据这一步中的几个属性,来选择处理这个请求的类和方法的,到此,RequestMappingHandlerMapping初始化结束。
2.4、RequestMappingHandlerAdapter的初始化
RequestMappingHandlerAdapter实现了InitializingBean接口,因此会在初始化时,调用afterPropertiesSet()方法:
public void afterPropertiesSet() {
// 首先初始化ResponseBody增强的bean,赋值给argumentResolvers属性
initControllerAdviceCache();
//初始化各种参数解析器
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//初始化@initBind参数解析器,赋值给initBinderArgumentResolvers 属性
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//初始化返回值的解析器,赋值给returnValueHandlers 属性
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
2.5、DispatcherServlet的初始化方法
DispatcherServlet的父类FrameworkServlet里面有个内部类ContextRefreshListener,ContextRefreshListener实现了ApplicationListener接口。
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
}
IOC容器创建完成以后,会发布ContextRefreshedEvent事件,ContextRefreshListener监听到此事件以后,进入onApplicationEvent()方法:
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
onRefresh(event.getApplicationContext());
}
FrameworkServlet的onRefresh()是个空实现,而子类DispatcherServlet重写了这个方法,initStrategies()方法内部,实现了DispatcherServlet的初始化逻辑
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
//MultipartResolver用于处理文件上传
initMultipartResolver(context);
//Spring的国际化配置
initLocaleResolver(context);
//Web用Theme来控制网页风格,一个主题就是一组静态资源
initThemeResolver(context);
//客户端发出Request时,DispatcherServlet将Request提交给HandlerMapping
//然后HandlerMapping返回响应的Controller
initHandlerMappings(context);
//HandlerAdapter用于处理Http请求
initHandlerAdapters(context);
//异常处理解析器
initHandlerExceptionResolvers(context);
//没有返回视图名称的时候,如何确定视图名称的组件
initRequestToViewNameTranslator(context);
//根据ModelAndView选择合适的View进行渲染
initViewResolvers(context);
//Flash attributes在重定向之前暂存,以便重定向之后还能使用
//FlashMap用于保持Flash attributes
initFlashMapManager(context);
}
其中initHandlerMappings()方法:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
//找到ApplicationContext及其父context中的HandlerMappings
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
//赋值给handlerMappings
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
//省略其他代码
}
DispatcherServlet在选用HandlerMapping的过程中,将根据我们所指定的一系列HandlerMapping的优先级进行排序,然后优先使用优先级在前的HandlerMapping,如果当前的HandlerMapping能够返回可用的Handler,DispatcherServlet则使用当前返回的Handler进行Web请求的处理,而不再继续询问其他的HandlerMapping。否则,DispatcherServlet将继续按照各个HandlerMapping的优先级进行询问,直到获取一个可用的Handler为止。
排序后的handlerMapping如图,前面分析的RequestMappingHandlerMapping被放在了集合的第一位。

initHandlerAdapters()方法:
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
//省略其他代码
}
DispatcherServlet通过HandlerMapping得到Handler后,会轮询HandlerAdapter模块,查找能够处理当前HTTP请求的HandlerAdapter实现,HandlerAdapter模块根据Handler类型,来选择某个HandlerAdapter,从而适配当前的HTTP请求。
排序后的HandlerAdapter:

同样前面分析的RequestMappingHandlerAdapter在集合的第一位。其他的初始化方法与initHandlerMapping和initHandlerAdapter类似,就不再累述了。
网友评论