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.");
}
}