Servlet生命週期瞭解
Servlet的生命(週期)是由容器(eg:Tomcat)管理的,換句話說,Servlet程式設計師不能用程式碼控制其生命。
載入和例項化:時機取決於web.xml的定義,如果有
初始化(init):例項化後會立馬進行初始化,也就是執行init方法,init方式只會執行一次。
請求處理:初始化後,Servlet就可以接受請求了,基本方式是執行Servlet介面中的service方法。
終止服務:容器會在合適的時候銷燬某個Servlet物件,這個策略取決於容器的開發者/商,銷燬時destroy方法會被呼叫。
核心處理請求流程圖
入口
前端控制器DispatcherServlet也是一個Servlet,他父類的父類HttpServletBean覆寫了Servlet介面的init方法,在容器第一次載入或者第一次請求時會觸發(延遲載入),這個方法是Sring Mvc初始化的入口。
啟動初始化
容器啟動
- Spring容器啟動過程,會執行Bean的載入、建立和初始化,此處以Controller層為例分析,暫不關注其他型別資源。
- RequestMappingHandlerMapping類也是其中一個Bean,負責解析所有標識有@Controller或者@RequestMapping註解的Bean。
- RequestMappingHandlerMapping的父類實現了InitializingBean介面,覆寫了afterPropertiesSet()方法,該介面是Spring的擴充套件點之一,在Bean初始化過程中,所i有屬性注入完畢之後,會執行一系列回撥(回撥入口:AbstractAutowireCapableBeanFactory#initializeBean),其中一個回撥會驗證當前類是否實現了InitializingBean介面,如果實現了會呼叫afterPropertiesSet()方法,此方法是解析Controller層路徑和方法對應關係的入口。
- 解析完畢之後會儲存在AbstractHandlerMethodMapping#MappingRegistry中,控制器方法HandlerMethod儲存了當前路徑對應方法的主要資訊,它只負責準備資料,封裝資料,而而不提供具體使用的方式方法。
- 在接收請求時會先根據路徑從urlLookup 中獲取匹配條件,然後根據匹配條件獲取控制器方法HandlerMethod。
class MappingRegistry {
// T:RequestMappingInfo => <請求匹配條件,控制器方法>
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
// T:RequestMappingInfo => <路徑,請求匹配條件>
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
}
public class HandlerMethod {
/** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
// Web控制器方法所在的Web控制器bean。可以是字串,代表bean的名稱;也可以是bean例項物件本身。
private final Object bean;
// Bean工程,如果bean屬性是Sring的beanName就可以用beanName獲取到對應的bean作用Handler
@Nullable
private final BeanFactory beanFactory;
// Web控制器方法所在的Web控制器bean的型別,如果該bean被代理,這裡記錄的是被代理的使用者類資訊
private final Class<?> beanType;
// Web控制器方法
private final Method method;
private final Method bridgedMethod;
// Web控制器方法的引數資訊:所在類所在方法,引數,索引,引數型別
private final MethodParameter[] parameters;
// 註解@ResponseStatus的code屬性
@Nullable
private HttpStatus responseStatus;
// 註解@ResponseStatus的reason屬性
@Nullable
private String responseStatusReason;
@Nullable
private HandlerMethod resolvedFromHandlerMethod;
....
}
策略初始化
protected void initStrategies(ApplicationContext context) {
// 初始化檔案解析器,用於支援伺服器的檔案上傳
initMultipartResolver(context);
// 初始化國際化解析器,用來提供國際化功能;
initLocaleResolver(context);
// 初始化主題解析器,用來提供皮膚主題功能;
initThemeResolver(context);
// 初始化處理器對映器
initHandlerMappings(context);
// 初始化處理器介面卡,為不同的處理器提供上下文執行環境;
initHandlerAdapters(context);
// 處理器異常解析器,用來解析處理器產生的異常;
initHandlerExceptionResolvers(context);
// 初始化檢視邏輯名稱轉換器,根據邏輯檢視的名稱找到具體的檢視。
// 當處理器沒有返回邏輯檢視名時,將請求的URL自動對映為邏輯檢視名;
initRequestToViewNameTranslator(context);
// 初始化檢視解析器,當控制器返回後,通過試圖解析器會把邏輯檢視名進行解析,從而定位實際檢視;
initViewResolvers(context);
// 初始化FlashMap管理器介面,負責重定向時,儲存引數到臨時儲存中
initFlashMapManager(context);
}
對映器初始化
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 預設獲取應用上下文所有的處理器對映
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 獲取所有的處理器對映
Map<String, HandlerMapping> 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 {
// 根據名稱獲取指定的bean:handlerMapping
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.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
// 獲取預設的處理器對映
// 從【DispatcherServlet.properties】檔案中讀取預設配置
// BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
介面卡初始化(和對映器邏輯一致)
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);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
請求處理
流程圖
doDispatch方法解析
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 2.獲取處理器對映器
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
// 獲取不到handler 拋異常或者返回404
this.noHandlerFound(processedRequest, response);
return;
}
// 4.獲取處理器介面卡器
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
// 6.迴圈呼叫攔截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 8.實際執行程式碼,handler通過反射執行控制器方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 預設檢視
this.applyDefaultViewName(processedRequest, mv);
// 10.迴圈呼叫攔截的postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 11.處理結果,進行檢視解析 & 模板引擎渲染 & request域填充
// 12.內部會呼叫攔截器的afterCompletion方法
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
// 目標方法完成之後執行
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
// 目標方法完成之後執行
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
獲取處理器對映器
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
// 核心方法獲取執行鏈
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 獲取handler
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
// 不滿足,返回
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
// 以handler為引數獲取執行鏈:建立一個執行鏈物件,handler賦值到內部變數,新增所有攔截器
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
...
...
return executionChain;
}
}
獲取處理器介面卡
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
// 核心判斷方法,找到支援該handler的介面卡
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
執行攔截器前置處理preHandle方法
HandlerExecutionChain#applyPreHandle
- 攔截器的preHandle方法任意一個返回false則訪問不到目標方法
- 攔截器的afterCompletion方法一定會執行
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
// 迴圈呼叫
if (!interceptor.preHandle(request, response, this.handler)) {
// 執行完畢攔截器的所有AfterCompletio方法後return
this.triggerAfterCompletion(request, response, (Exception)null);
// 一個返回false即停止迴圈
return false;
}
}
}
return true;
}
執行控制器的目標方法
InvocableHandlerMethod#doInvoke
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(this.getBridgedMethod());
try {
// method.invoke(obj,args);
// 反射呼叫目標類的目標方法
// 目標方法:this.getBridgedMethod()
// this.getBean()獲取handler中的bean,即為容器中的目標類例項/可能是一個CGLIB增強後的代理物件
return this.getBridgedMethod().invoke(this.getBean(), args);
} catch (IllegalArgumentException var4) {
this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
String text = var4.getMessage() != null ? var4.getMessage() : "Illegal argument";
throw new IllegalStateException(this.formatInvokeError(text, args), var4);
} catch (InvocationTargetException var5) {
Throwable targetException = var5.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException)targetException;
} else if (targetException instanceof Error) {
throw (Error)targetException;
} else if (targetException instanceof Exception) {
throw (Exception)targetException;
} else {
throw new IllegalStateException(this.formatInvokeError("Invocation failure", args), targetException);
}
}
}
處理返回結果 & 執行攔截器afterCompletion方法
DispatcherServlet#processDispatchResult
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) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if (mv != null && !mv.wasCleared()) {
// a.檢視解析 & 模板引擎渲染
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No view rendering, null ModelAndView returned.");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
// b.呼叫攔截器afterCompletion方法
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
a.檢視解析 & 模板引擎渲染
DispatcherServlet#render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
response.setLocale(locale);
String viewName = mv.getViewName();
View view;
if (viewName != null) {
// 檢視解析
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 模板引擎渲染
view.render(mv.getModelInternal(), request, response);
} catch (Exception var8) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "]", var8);
}
throw var8;
}
}
b.呼叫攔截器afterCompletion方法,一定會執行
HandlerExecutionChain#afterCompletion
public void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
}
}
同一路徑時啟動報錯原始碼位置
AbstractHandlerMethodMapping#assertUniqueMethodMapping
private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) {
// 根據路徑資訊獲取方法資訊
// 一個路徑對應2個方法時第二個方法解析時會獲取到上個方法的資訊
HandlerMethod handlerMethod = this.mappingLookup.get(mapping);
// 根據路徑獲取到方法資訊 並且 2個不是同一個方法時報錯提示已經存在
if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException(
"Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" +
newHandlerMethod + "\nto " + mapping + ": There is already '" +
handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
}
}