我们接着上一篇文章 SpringMVC源码解析(上) 来继续分析,下面来看DispatcherServlet的源码详细解析
init()方法用来初始化资源;
doGet()/doPost()等方法用来接收并处理请求;
下面就按照这两块来分析DispatcherServlet源码
1.DispatcherServlet.init(默认实现在HttpServletBean类中) 1)init()初始化
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
try {
// 1.获取web.xml中关于DispatcherServlet的init-parm配置,封装为PropertyValues
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
// 2.将当前DispatcherServlet封装成BeanWrapper
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
// 3.将PropertyValues的参数封装到BeanWrapper
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
// 4.初始化资源(重要方法)
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
2)initServletBean()方法默认在子类FrameworkServlet中实现
protected final void initServletBean() throws ServletException {
...
try {
this.webApplicationContext = initWebApplicationContext();// 重要方法
initFrameworkServlet();
}
...
}
// initWebApplicationContext()
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
...
// 1.先去查看当前应用中是否有ApplicationContext,如果有就用这个,没有的话则新建
if (wac == null) {
wac = createWebApplicationContext(rootContext);// 在3)中详细分析
}
if (!this.refreshEventReceived) {
// 2.重要的初始化方法,会在这里初始化HandlerMapping、Resolver等各种资源
onRefresh(wac);// 会在4)中详细分析
}
...
return wac;
}
3)FrameworkServlet.createWebApplicationContext()分析如何创建ApplicationContext
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class contextClass = getContextClass();
...
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac);
return wac;
}
//configureAndRefreshWebApplicationContext()
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
...
// 初始化各种资源
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
// 重要方法,最终实现在AbstractApplicationContext.refresh(),
// 会初始化一个ApplicationContext,加载bean到Spring中
wac.refresh();
}
4)FrameworkServlet.onfresh()默认实现在DispatcherServlet
@Override
protected void onRefresh(ApplicationContext context) {
// 主要是为了刷新DispatcherServlet中的一些全局变量,如multipartResolver、handlerMappings等
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
// 1.获取Spring中的相关resolver_bean,这个比较简单,直接context.getBean()来获取
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
// 2.加载容器中合适的HandlerMapping(重要方法)
initHandlerMappings(context);// 在5)中详细分析
// 3.加载容器中合适的HandlerAdapter
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
// 4.初始化 viewResolvers
initViewResolvers(context);
initFlashMapManager(context);
}
5)initHandlerMappings(context)初始化handlerMappings信息
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 1.默认detectAllHandlerMappings为true,所以直接走该段逻辑
if (this.detectAllHandlerMappings) {
// 真正实现就是这句话
// 代码实现:ListableBeanFactory.getBeansOfType(type, includeNonSingletons, allowEagerInit)
// 主要就是从容器中获取关于HandlerMapping接口的实现
// 类DelegatingWebMvcConfiguration实现了@configuration,并且在其父类WebMvcConfigurationSupport中
/**
* @Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {}
@Bean
public BeanNameUrlHandlerMapping beanNameHandlerMapping() {}
*
*/
// 默认加载这两个bean到容器中,则HandlerMappings会添加这两个bean
Map matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// 2.如果获取不到handlerMappings,则查询默认值
// 默认值在spring-webmvc.jar下DispatcherServlet.properties中
// 默认值内容为:org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
//org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
注意:由上述代码分析可知,RequestMappingHandlerMapping类在Spring容器初始化的时候就会被加载进来,下面分析下这个类, 有其类层次结构可知其实现了InitializingBean接口,在该bean初始化的时候会默认执行其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();// 重点看这里
}
// super.afterPropertiesSet()
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
...
// 1.默认加载所有的bean
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class beanType = null;
try {
// 2.获取该bean
beanType = getApplicationContext().getType(beanName);
}
...
// 3.如果该bean有Controller注解或者RequestMapping注解,则将该RequestMapping对应的方法注册到Handler中
// isHandler()方法内容体为 AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);// 重要方法,主要的解析Controller中的方法就在这
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
// detectHandlerMethods()
protected void detectHandlerMethods(final Object handler) {
Class handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class userType = ClassUtils.getUserClass(handlerType);
// 1.获取该handler类所有的注解方法,对应于请求路径
Map methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup() {
@Override
public T inspect(Method 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);
}
// 2.将注解方法注册到RequestMappingHandlerMapping中
for (Map.Entry entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
总结1:初始化的主要内容包括两部分:
1)创建ApplicationContext,加载bean到容器中
2)初始化HandlerMappings等资源
3)加载实现了HandlerMapping接口的类,如RequestMappingHandlerMapping,在初始化该bean完成的时候,调用afterPropertiesSet()方法,完成对Controller的检索,将所有的@RequestMapping方法注册到RequestMappingHandlerMapping中
2.DispatcherServlet.doGet()方法具体实现
可知其默认实现在FrameworkServlet类中,方法如下:
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
try {
doService(request, response);
}
...
}
// doService()默认实现在DispatcherServlet类中,方法如下:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
try {
doDispatch(request, response);
}
...
}
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 {
// 1.判断是否带附件的请求,如果是,则转换为对应请求类型
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2.获取HandlerMapping,主要是为了寻找请求对应的Controller类方法
// 这个方法之前已经放在RequestMappingHandlerMapping中了
mappedHandler = getHandler(processedRequest);// 在1)中详细分析
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 3.获取HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
// 4.调用HandlerAdapter.handler方法
// handler方法会先执行拦截器的方法,然后执行Controller的对应方法获取对应的ModelAndView,也就是对应的视图
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 在2)中详细分析
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
...
// 5.跳转到指定页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);// 在3)中详细分析
}
...
}
1)getHandler(processedRequest)根据请求获取对应HandlerExecutionChain
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 1.获取请求对应的Handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 2.封装请求链,主要是为了把请求方法对应的拦截器添加到HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
// getHandlerInternal()获取请求对应的Handler
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 1.获取请求路径(去掉项目名之后的信息)
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
// 2.从之前注册到RequestMappingHandlerMapping的HandlerMethod map中查找与请求路径匹配的HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
2)ha.handle(processedRequest, response, mappedHandler.getHandler())
兜兜转转,笔者该例的ha实现类为RequestMappingHandlerAdapter,其handle方法具体实现在该类的handleInternal()方法中
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// synchronizeOnSession默认为false
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 重要方法,请求调用Controller具体实现方法就在这里实现
mav = invokeHandlerMethod(request, response, handlerMethod);
}
...
return mav;
}
//invokeHandlerMethod()
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
...// 主要是一堆数据封装
// 1.在这个方法中会调用Controller类实现方法,并获得响应
invocableMethod.invokeAndHandle(webRequest, mavContainer);// 下面详细分析该方法
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 2.获取响应对应的ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest); // 下面详细分析该方法
}
finally {
webRequest.requestCompleted();
}
}
// invokeAndHandle()真正的Controller层方法调用
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 具体实现在这
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
...
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
...
}
// invokeForRequest
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 1.获取请求参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
// 2.Method反射来执行方法
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
// doInvoke
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 即Method.invoke(Object obj, Object... args)
return getBridgedMethod().invoke(getBean(), args);
}
...
}
// getModelAndView()调用完Controller方法之后,返回对应的视图界面
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
// 直接从mavContainer中获取viewName并封装即可
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
经过上面的一堆分析之后,我们已经根据请求调用了对应Controller的方法,并且根据方法返回值获取对应的视图页面名称
下面就是最后一步了,跳转到指定的视图
3)processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException) private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
...
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
// 真正实现方法在这
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
...
}
// render()
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// 1.获取对应的View信息,view包含了ModelAndView中viewName对应的页面全路径信息
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
...
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 2.真正跳转方法,笔者该例中默认实现在AbstractView中
view.render(mv.getModelInternal(), request, response);
}
...
}
// view.render()
public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}
Map mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);// 重点在这,实现类为当前调用类,笔者的为InternalResourceView类
}
// renderMergedOutputModel()
protected void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1.获取转发路径
String dispatcherPath = prepareForRendering(request, response);
// 2.获取RequestDispatcher
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(request, response);
}
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
// 3.forward转发模式,
rd.forward(request, response);
}
}
总结3):分析完之后,可以发现,无论方法封装了多少层,其最本质的方法也就是我们之前在 SpringMVC源码解析(上)中使用Servlet进行转发时候的那样
request.getRequestDispatcher("/res.html").forward(request, response);
总结:通过两篇博客来分析了SpringMVC的具体调用过程,主要还是分两步走:
1)初始化bean,将HandlerMapping实现类相关bean加载到Spring中,这些bean在初始化完成之后,也会扫描所有的@RequestMapping方法,并注册到该HandlerMapping中去
2)根据请求路径获取对应的HandlerExecutionChain(主要包含request相对应的Controller处理类和拦截器列表),然后调用HandlerAdapter相关方法来执行Controller方法和拦截器方法,并返回视图界面名称。根据视图名称进行跳转操作,完成响应
参考:Spring源码深度解析(郝佳)