從Jetty啓動流程能夠看到,啓動上下文以後,緊接着就開始初始化servlet,調用init方法web
private synchronized void initServlet()
throws ServletException
{
...
//調用Servlet的init方法
_servlet.init(_config);
...
}
複製代碼
從web.xml文件中能夠看到,這個servlet就是DispatcherServlet,對應的init方法在父類GenericServlet中spring
public void init(ServletConfig config) throws ServletException {
//這裏servletconfig就被傳下來
this.config = config;
//執行子類的init方法
this.init();
}
複製代碼
對應在 HttpServletBean中json
public final void init() throws ServletException {
...
initServletBean();
}
複製代碼
在FrameworkServlet中實現對應的spring的servlet的初始化bash
protected final void initServletBean() throws ServletException {
…
this.webApplicationContext = initWebApplicationContext();
…
}
複製代碼
對應的初始化web容器,首先也會去查詢是否已經初始化過了mvc
protected WebApplicationContext initWebApplicationContext() {
//獲取根webapplicationcontext,這就是在IOC容器初始化的時候塞入的值,若是IoC容器已經初始化完成,那麼這裏的值確定不是null
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
//若是沒有執行過webcontextapplication的refresh,那麼再執行一次
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
//這個過程就相似IOC的啓動了
configureAndRefreshWebApplicationContext(cwac);
}
}
}
...
if (!this.refreshEventReceived) {
//沒有執行過refresh則執行一次
onRefresh(wac);
}
….
return wac;
}
複製代碼
對於這個時間點的DispatcherServlet啓動來講,核心在於 onRefresh
,它會去初始化各類resolverapp
protected void onRefresh(ApplicationContext context) {
…
initMultipartResolver(context);
...
initHandlerMappings(context);
...
initViewResolvers(context);
…
}
複製代碼
它會從容器中讀取是否包含 bean ‘multipartResolver'webapp
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver」; ... private void initMultipartResolver(ApplicationContext context) { ... this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class); ... } 複製代碼
MultipartResolver是用來解決文件上傳問題ide
默認本身去掃描全部HandlerMapping類型的post
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
//默認這裏執行主動探測,這裏的實現其實就是從BeanFactory中獲取全部已經註冊了的,且類型是HandlerMapping的類的名字,而後再從BeanFactory中獲取全部這個名字的bean做爲返回
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
...
if (this.handlerMappings == null) {
//沒有handlerMapping,則使用默認的。
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
複製代碼
在沒有配置的狀況下,處理映射的類配置在spring自帶的文件DispatcherServlet.properties
中,默認handlerMapping的類爲ui
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
複製代碼
HandlerMapping負責定義請求和處理請求的對象之間的映射
以RequestMappingHandlerMapping
爲例。當獲取到對應的名字後
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
//獲取默認的配置
String value = defaultStrategies.getProperty(key);
….
//經過反射構建class對象
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
//從beanFactory中獲取對象,其實就是調用createBean方法
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
….
}
複製代碼
對於beanFactory來講,建立一個bean或經歷它的完整生命週期,通過多層查找,能夠看到以下代碼
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
...
instanceWrapper = createBeanInstance(beanName, mbd, args);
...
final Object bean = instanceWrapper.getWrappedInstance();
...
Object exposedObject = bean;
...
exposedObject = initializeBean(beanName, exposedObject, mbd);
...
}
複製代碼
執行一些列的生命名週期方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
...
//執行各類aware方法
invokeAwareMethods(beanName, bean);
…
//執行初始化以前的BeanPostProcessor相關方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
…
//執行初始化bean方法
invokeInitMethods(beanName, wrappedBean, mbd);
…
//執行初始化以後的BeanPostProcessor相關方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
...
}
複製代碼
-aware 方法
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } } 複製代碼
初始化bean又包含了相關生命週期要執行的邏輯
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
…
//執行afterPropertiesSet
((InitializingBean) bean).afterPropertiesSet();
...
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//執行本身的initMethod方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
複製代碼
對於 RequestMappingHandlerMapping 繼承了接口ApplicationContextAware
和 InitializingBean
,都屬於bean生命週期中的一環。
RequestMappingHandlerMapping的父類本身持有一個applicationContext的引用
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
...
else if (this.applicationContext == null) {
...
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
initApplicationContext(context);
}
...
}
複製代碼
從父類開始往下去執行對應的方法
protected void initApplicationContext() throws BeansException {
…
//探測全部的interceptor,即找到全部類MappedInterceptor【這對應 mvc-interceptor標籤】和實現了接口HandlerInterceptor的攔截器
detectMappedInterceptors(this.adaptedInterceptors);
//初始化interceptor
initInterceptors();
}
複製代碼
public void afterPropertiesSet() {
…
//getCandidateBeanNames默認就是獲取全部的bean
for (String beanName : getCandidateBeanNames()) {
//判斷 bean 的名字是不是 「scopedTarget.」 字符串開頭
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
…
}
複製代碼
查到bean後,開始識別是不是用來處理請求的
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
...
beanType = obtainApplicationContext().getType(beanName);
…
//isHandler即判斷這個beanType是否包含註解 Controller 或者 RequestMapping
if (beanType != null && isHandler(beanType)) {
//找到這個註解bean的全部方法,構建映射關係
detectHandlerMethods(beanName);
}
}
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
複製代碼
探測handler的方法分紅兩個主要部分
protected void detectHandlerMethods(Object handler) {
…
//找到這個bean的方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
//找到方法對應的RequestMapping註解,將它的path等參數封裝成RequestMappingInfo返回
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
...
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//註冊handler,在內部建立HandlerMethod,在urlLookup中存儲 url和mapping的關係,而mapping和HandlerMethod則存儲在mappingLookup中
registerHandlerMethod(handler, invocableMethod, mapping);
});
...
}
複製代碼
同handlerMapping,默認類爲
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
複製代碼
根據view的名字來找到對應的View。View則負責來渲染內容
從Jetty請求過程能夠看到,執行請求對應着的是servlet的service方法,對應spring來講,他就是DispatcherServlet
protected void doService(HttpServletRequest request, HttpServletResponse response) {
…
//請求總設置applicationContext
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
…
//進行請求分發
doDispatch(request, response);
…
}
doDispatch負責把一次請求分配給對應的handler來處理
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
ModelAndView mv = null;
...
//若是請求存在分段文件,則轉換成Multipart,好比MultipartHttpServletRequest
processedRequest = checkMultipart(request);
…
//獲取對應請求的handler
mappedHandler = getHandler(processedRequest);
…
//返回這個hander對應的適配器,好比對於HandlerMethod子類返回的就是AbstractHandlerMethodAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
…
//調用interceptor的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
…
//執行處理邏輯
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
…
//掉interceptor的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
….
//處理結果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
...
}
複製代碼
getHandler詳細處理以下
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//內部根據請求的路徑執行lookupHandlerMethod(lookupPath, request),而它就會從 urlLookup.get(urlPath)中查到對應的mapping,再查到HanlerMethod
Object handler = getHandlerInternal(request);
…
//匹配路徑的攔截器全都加到handler鏈路裏面來
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
...
return executionChain;
}
複製代碼
handler核心邏輯以下
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...
//將handlerMethod進行包裝,以便後續經過反射執行
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
。。。
//建立ModelAndView的容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
…
//經過反射執行
invocableMethod.invokeAndHandle(webRequest, mavContainer);
…
//獲取ModeAndView,從內部能夠看到,它會自行建立一個ModelAndView對象
return getModelAndView(mavContainer, modelFactory, webRequest);
...
}
複製代碼
得到handler的結果以後,調用processDispatchResult,核心就是進行render
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
...
render(mv, request, response);
...
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
….
View view;
//獲取視圖的名字
String viewName = mv.getViewName();
//根據名字獲取對應的視圖
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
…
//執行渲染
view.render(mv.getModelInternal(), request, response);
...
}
複製代碼
執行render方法來源與全部render的父類AbstractView的render方法
@Overridepublic void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
….
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
//真正執行渲染
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
複製代碼
好比返回的是JSON對象,那麼實際狀況以下
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
Object value = this.filterModel(model);
//值封裝成json
String text = JSON.toJSONString(value, this.serializerFeatures);
byte[] bytes = text.getBytes(this.charset);
Object stream = this.updateContentLength?this.createTemporaryOutputStream():response.getOutputStream();
//結果寫入outpuststream
((OutputStream)stream).write(bytes);
if(this.updateContentLength) {
//返回
this.writeToResponse(response, (ByteArrayOutputStream)stream);
}
}
複製代碼
對於Freemarker來講,就是執行FreemarkerView.renderMergedTemplateModel方法,內部執行doRender
protected void doRender(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
exposeModelAsRequestAttributes(model, request);
SimpleHash fmModel = buildTemplateModel(model, request, response);
Locale locale = RequestContextUtils.getLocale(request);
//這裏就是調用Freemarker的template來處理對應的數據填充等等 template.process(model, response.getWriter());
processTemplate(getTemplate(locale), fmModel, response);
}
複製代碼
至此一次請求結束