SpringMVC的請求處理流程圖

總結(jié)
1、請求進(jìn)入DispatcherServlet,由DispatcherServlet 從HandlerMappings中提取對應(yīng)的Handler
2、根據(jù)Handle,然后去尋找對應(yīng)的處理器適配器(HandlerAdapter),拿到對應(yīng)HandlerAdapter后,這時候開始調(diào)用對應(yīng)的Handler處理業(yè)務(wù)邏輯
3、執(zhí)行完成之后返回一個ModeAndView,將結(jié)果交給我們的ViewResolver通過視圖名稱查找出對應(yīng)的視圖然后返回
4、渲染視圖:返回渲染后的視圖并響應(yīng)請求
請求處理器的初始化
1、DispacterServlet中的靜態(tài)塊
static {
/**
* static靜態(tài)塊,在類加載的時候執(zhí)行
* 加載springWvc的默認(rèn)系統(tǒng)配置文件 DispatcherServlet.properties
* 配置了 HandlerAdapter HandlerMapping ThemeResolver LocaleResolver ....
* 放入到 defaultStrategies 對象中
*/
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
DispatcherServlet.properties文件
# 僅列出部分
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
2、當(dāng)Servlet容器啟動的時候,tomcat會調(diào)用這個DispatcherServlet的init方法
// HttpServletBean#init
public final void init() throws ServletException {
// 執(zhí)行子類 FrameServlet的initServletBean方法
initServletBean();
}
// FrameworkServlet#initServletBean
protected final void initServletBean() throws ServletException {
// 初始化web環(huán)境 WebApplicationContext ==child==> ConfigurableWebApplicationContext
this.webApplicationContext = initWebApplicationContext();
// 調(diào)用了initFrameworkServlet方法,這是一個空方法
initFrameworkServlet();
}
// FrameworkServlet#initWebApplicationContext
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.webApplicationContext;
// 配置并且刷新容器
configureAndRefreshWebApplicationContext(cwac);
}
// FrameworkServlet#configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
// 添加了一個容器刷新的監(jiān)聽器 => ContextRefreshListener
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// 空方法
postProcessWebApplicationContext(wac);
// 容器的初始化共組
applyInitializers(wac);
// 刷新容器,走到AbstractApplicationContext中的refresh方法
wac.refresh();
}
3、容器刷新時觸發(fā)的監(jiān)聽器ContextRefreshListener
// FrameworkServlet.ContextRefreshListener
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
}
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
synchronized (this.onRefreshMonitor) {
onRefresh(event.getApplicationContext());
}
}
// 調(diào)用子類的onRefresh方法
// DispatcherServlet#onRefresh
protected void onRefresh(ApplicationContext context) {
// 初始化策略組件
initStrategies(context);
}
4、初始化組件
// DispatcherServlet#initStrategies
protected void initStrategies(ApplicationContext context) {
// 初始化文件上傳組件 beanName="multipartResolver"
initMultipartResolver(context);
// 初始化國際化組件 beanName="localeResolver"
initLocaleResolver(context);
// 初始化主題解析器,利用spring來做 beanName="themeResolver"
initThemeResolver(context);
// 初始化處理映射器 beanName="handlerMapping"
initHandlerMappings(context);
// 初始化處理器適配器 beanName="handlerAdapter"
initHandlerAdapters(context);
// 初始化異常處理器 beanName="handlerExceptionResolver"
initHandlerExceptionResolvers(context);
// 視圖解析器,在view為空時,根據(jù)請求來獲取視圖名稱 beanName="viewNameTranslator"
initRequestToViewNameTranslator(context);
// 初始化視圖解析器 beanName="viewResolver"
initViewResolvers(context);
// 重定向數(shù)據(jù)管理器 beanName="flashMapManager"
initFlashMapManager(context);
}
初始化的組件中MultipartResolver、LocaleResolver、ThemeResolver、RequestToViewNameTranslator和FlashMapManager的初始化是直接去容器中獲取對應(yīng)的bean對象。
其他的組件默認(rèn)會去容器中尋找所有的 對應(yīng)類型 的對象。如果在容器中沒有找到對應(yīng)的對象,那么就會向容器中注冊 DispatcherServlet.properties 文件中的對應(yīng)的類。
// 去DispatcherServlet.properties文件中獲取 strategyInterface 對應(yīng)的組件
// 找到之后會將組件注冊到DispatcherServlet的對應(yīng)屬性上
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
// 傳入的class全名,就對應(yīng)了DispatcherServlet.properties中的key
String key = strategyInterface.getName();
// 從配置文件中拿出配置
String value = defaultStrategies.getProperty(key);
if (value != null) {
// 截取value中的 , 返回一個className 的數(shù)組
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
// 根據(jù)反射創(chuàng)建出這個class對象
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
// 根據(jù)這個class 去createBean,這里就可以將 HandlerMapping 的組件放入容器中
Object strategy = createDefaultStrategy(context, clazz);
// 最后把策略對象返回
strategies.add((T) strategy);
}
return strategies;
} else {
return new LinkedList<>();
}
}
請求處理器處理請求
SpringMVC的核心處理器:DispatcherServlet,它本質(zhì)上也是一個HttpServlet,在配置SpringMVC的時候,我們會讓這個servlet隨著servlet容器的啟動而啟動(load-on-startup),并且攔截所有對當(dāng)前應(yīng)用程序的請求。
所以當(dāng)請求來了之后,首先會調(diào)用HttpServlet#service方法。具體會調(diào)用父類FrameworkServlet#service
// FrameworkServlet#service
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
// // 增加對HttpMethod.PATCH的支持
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
} else {
// HttpServlet#service 進(jìn)行請求類型的分發(fā) -> 走到doGet/doPost/doPut
// 最終都會和上面的一致調(diào)用 processRequest(request, response);
super.service(request, response);
}
}
處理請求之前的一些準(zhǔn)備
org.springframework.web.servlet.FrameworkServlet#processRequest
-> org.springframework.web.servlet.DispatcherServlet#doService
-> org.springframework.web.servlet.DispatcherServlet#doDispatch
處理請求的核心方法:DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 檢查是否存在文件上傳
HttpServletRequest processedRequest = checkMultipart(request);
boolean multipartRequestParsed = (processedRequest != request);
// 確定當(dāng)前請求是由哪一種handlerMapping來處理
// 一種是選擇一個bean來處理,另一種是映射到一個方法上
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
// 根據(jù)當(dāng)前的請求的 handlerMapping 來決定使用哪一種處理器適配器
// HttpRequestHandlerAdapter
// SimpleControllerHandlerAdapter
// RequestMappingHandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 執(zhí)行所有配置這個uri的攔截器的 preHandle 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
// 只要存在一個攔截器的 preHandle 方法返回false,這里就會直接return
return;
}
/** 調(diào)用實(shí)際的處理器來處理請求
如果是匹配一個類的話,這里會直接把這個映射對象傳入 => mappedHandler.getHandler()
HttpRequestHandlerAdapter => handle() => handler.handleRequest(request, response)
SimpleControllerHandlerAdapter => handle() => handler.handleRequest(request, response);
RequestMappingHandlerAdapter
=> AbstractHandlerMethodAdapter#handle
=> RequestMappingHandlerAdapter#handleInternal
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
*/
// 是否是異步請求
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如果存在mv對象,但是在mv中不存在view,這里就會應(yīng)用一個默認(rèn)的視圖對象
applyDefaultViewName(processedRequest, mv);
// 執(zhí)行所有配置這個uri的攔截器的 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 處理返回值,渲染頁面,返回響應(yīng)...
// 在這里面的最后一個執(zhí)行所有配置這個uri的攔截器的 afterCompletion 方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
doDispatch方法就是SpringMVC中請求處理流程的具體代碼實(shí)現(xiàn)。
核心組件 - HandlerMapping
在DispatcherServlet.properties中HandlerMapping組件存在兩種實(shí)現(xiàn)BeanNameUrlHandlerMapping和RequestMappingHandlerMapping
根據(jù)HandlerMapping中的getHandler方法來確定使用哪一種HandlerMapping。
// DispatcherServlet#getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings == null) return null;
// 遍歷所有的handlerMappings
for (HandlerMapping mapping : this.handlerMappings) {
// 這里返回這個請求對應(yīng)的攔截器鏈
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) return handler;
}
}
這里的getHandler方法非常關(guān)鍵,它不僅找出了需要使用的HandlerMapping還會去構(gòu)建好攔截器鏈。
public final HandlerExecutionChain getHandler(HttpServletRequest request) {
// 確定使用哪一類的請求處理器
// AbstractHandlerMethodMapping.getHandlerInternal -> RequestMappingHandlerMapping
// AbstractUrlHandlerMapping.getHandlerInternal -> BeanNameUrlHandlerMapping
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// 構(gòu)建攔截器鏈
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
HandlerMapping
1、AbstractHandlerMethodMapping.getHandlerInternal
// @RequestMapping這種servlet
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// uri localhost:9090/index => /index
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 讀鎖
this.mappingRegistry.acquireReadLock();
try {
// 根據(jù)uri獲取對應(yīng)的處理方法
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} finally {
this.mappingRegistry.releaseReadLock();
}
}
2、AbstractUrlHandlerMapping.getHandlerInternal
// @Component("/index/2") 這種controller
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// handlerMap<String, Object>中找可以找到
Object handler = lookupHandler(lookupPath, request);
if (handler != null) {
return handler;
}
// 省略部分代碼
}
構(gòu)建攔截器鏈
只有在找出對應(yīng)的HandlerMapping后才會構(gòu)建攔截器鏈
// AbstractHandlerMapping#getHandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// uri
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 遍歷所有的攔截器 我們自己實(shí)現(xiàn)了HandlerInterceptor會被springMVC包裝為MappedInterceptor
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
調(diào)用MappedInterceptor#matches進(jìn)行攔截器匹配
// addPathPatterns -> includePatterns
// excludePathPatterns -> excludePatterns
public boolean matches(String lookupPath, PathMatcher pathMatcher) {
PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher);
if (!ObjectUtils.isEmpty(this.excludePatterns)) {
for (String pattern : this.excludePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return false;
}
}
}
if (ObjectUtils.isEmpty(this.includePatterns)) {
return true;
}
for (String pattern : this.includePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return true;
}
}
return false;
}
獲取處理器適配器
這里的handlerAdapters默認(rèn)就是DispatcherServlet.properties中配置的三種攔截器適配器
- HttpRequestHandlerAdapter 匹配HttpRequestHandler處理器
- SimpleControllerHandlerAdapter 匹配實(shí)現(xiàn)了Controller接口或繼承了AbstractController的類
- RequestMappingHandlerAdapter 匹配HandlerMethod,@Controller注解
// HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 核心的supports方法
if (adapter.supports(handler)) {
return adapter;
}
}
}
}
// HttpRequestHandlerAdapter#supports
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
// SimpleControllerHandlerAdapter#supports
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
// AbstractHandlerMethodAdapter#supports
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
// RequestMappingHandlerAdapter#supportsInternal
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
攔截器回調(diào) - preHandle
// if (!mappedHandler.applyPreHandle(processedRequest, response)) {}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
// 每一個攔截器的 preHandle 需要返回true,整個請求處理才能繼續(xù)向下執(zhí)行
if (!interceptor.preHandle(request, response, this.handler)) {
// 如果有一個攔截器的 preHandle 方法返回了false,就會直接執(zhí)行直接攔截器 afterCompletion 方法,并返回false
triggerAfterCompletion(request, response, null);
// 返回false意味著這個請求的處理就到此結(jié)束了
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
處理器處理請求
以處理@Controller注解為例:AbstractHandlerMethodAdapter#handle
// mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
/** 調(diào)用子類的 handleInternal 方法
* 不同的處理器適配器實(shí)現(xiàn)了不同功能的 handleInternal 方法
* RequestMappingHandlerAdapter#handleInternal 處理@RequestMapping方法映射
*/
return handleInternal(request, response, (HandlerMethod) handler);
}
// RequestMappingHandlerAdapter#handleInternal
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// 在這個同步塊中執(zhí)行controller回調(diào)方法
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
// 執(zhí)行映射方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// json 數(shù)據(jù)格式的響應(yīng)在上面就完成了 invokeHandlerMethod 方法中
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
回調(diào)攔截器 - postHandle
檢查返回的ModelAndView和回調(diào)攔截器 - postHandle
// 如果存在mv對象,但是在mv中不存在view,這里就會應(yīng)用一個默認(rèn)的視圖對象
applyDefaultViewName(processedRequest, mv);
// 執(zhí)行所有配置這個uri的攔截器的 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 是否需要創(chuàng)建默認(rèn)的視圖對象
private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) {
if (mv != null && !mv.hasView()) {
// 存在mv對象,但是不存在view對象才會執(zhí)行到這里:DefaultRequestToViewNameTranslator
// DefaultRequestToViewNameTranslator#getViewName 方法
// 會根據(jù)請求的URI返回視圖名稱,去除后綴,前后/,如果完全匹配,就返回請求的URI
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
調(diào)用攔截器 - afterCompletion
// processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,HandlerExecutionChain mappedHandler,
ModelAndView mv,Exception exception) {
boolean errorView = false;
if (exception != null) {
// 如果存在異常,就把異常交給HandlerExceptionResolver來處理
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 調(diào)用 HandlerExceptionResolver#resolveException
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 是否返回了一個需要渲染的視圖
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
// 渲染視圖
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// 在視圖渲染等一切工作完成之后執(zhí)行攔截器的 afterCompletion 方法
// interceptor.afterCompletion(request, response, this.handler, ex);
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
SpringMVC對于beanName請求的處理
如果一個請求可以匹配到一個實(shí)現(xiàn)了Controller接口或者繼承了AbstractController的bean對象。那么可以直接調(diào)用接口或者抽象方法去處理請求。
// SimpleControllerHandlerAdapter -> 直接調(diào)用Controller接口的方法
// AbstractController會在handleRequest中調(diào)用子類的handleRequestInternal方法
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
// HttpRequestHandlerAdapter
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}