HttpServletBean
httpServletBean中Environment使用的是StandardServletEnvironment
StandardServletEnvironment
其中propertySources属性封装了如下信息:
servletContext 和 servletConfig
jndiProperty
系统环境变量
系统属性
//frameworkServlet中初始化 @Override public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) { WebApplicationContextUtils.initServletPropertySources( this.getPropertySources(), servletContext, servletConfig);//servletContext 和 servletConfig }
//AbstractEnvironment 构造方法中调用,构造StandardServletEnvironment对象时就有了。 @Override protected void customizePropertySources(MutablePropertySources propertySources) { propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME)); propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME)); if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) { propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));//jndiProperty } super.customizePropertySources(propertySources); }
@Override protected void customizePropertySources(MutablePropertySources propertySources) { propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));//系统属性 propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));//系统环境变量 }
init()
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);//this就是之后的DispatcherServlet
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));//注册Editor,复合resource类的,就用ResourceEditor来编辑
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);//将ServletConfig设置到dispatcherServlet
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
// Let subclasses do whatever initialization they like.
initServletBean();//模版方法
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
HttpServletBean主要作用
- 定义Environment
- 设置ServletConfig
FrameworkServlet
implements ApplicationContextAware
从spring中获取WebApplicationContext
initServletBean()
@Override
protected final void initServletBean() throws ServletException {
...
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
...
}
protected WebApplicationContext initWebApplicationContext() {
//获取spring的容器,从ServletContext#getAttribute(WebApplicationContext.class.getName() + ".ROOT")
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
//将spring容器设置为springmvc容器的父容器
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
//this.webApplicationContext = null & wac = null 是什么情况?
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
//通过配置servlet中的contextAttribute参数,从ServletContext中获取指定名字的webApplicationContext
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
// 留给dispatcherServlet
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
// FrameworkServlet.class.getName() + ".CONTEXT." + getServletName();
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
作用:
- 初始化WebApplicationContext 从ServletContext中获取
- initFrameworkServlet模版方法
servlet的webApplicationContext
已经构造好了webApplicationContext,在servlet构造方法中传入现有的对象。(主要用于servlet3.0以后,ServletContext.addServlet)
webApplication已经在ServletContext中了。可以通过配置来从servletContext中根据contextAttribute获取现有webApplicationContext
spring org.springframework.web.servlet.DispatcherServlet contextAttribute hehe contextConfigLocation classpath:spring-mvc.xml 1 true 自己创建(正常情况)
webApplicationContext 中的内容
- environment
- parent
- contextConfigLocation :web.xml中配置,默认WEB-INFO/[servletname]-Servlet.xml
- servletContext
- servletConfig
- namespace
- applicationListener : ContextRefreshedEvent监听器,收到event后调用onRefresh() 方法
- postProcessWebApplicationContext() 后置处理
重写doGet doPost.....
将doXXX方法全部交由processRequest() 方法。doOptions 和 doTrace 根据参数判断自己处理还是交给父类
processRequest
- 对LocaleContext和RequestAttributes设置和恢复
- doService()
- 处理完后发布publishRequestHandledEvent
ServletRequestAttributes封装了request,可以从request和session中取值。
requestAttributes.requestCompleted();执行后,不能再对requestAttributes进行操作。
LocaleContextHolder/RequestContextHolder
//根据request设置LocaleContextHolder/RequestContextHolder,可提供locale和request,在service层。
initContextHolders(request, localeContext, requestAttributes);
localeContextHolder、inheritableLocaleContextHolder可以被子线程继承???
没搞懂localeContextHolder inheritableLocaleContextHolder两个ThreadLocal变量的作用,希望大神帮忙解答。
resetContextHolders(request, previousLocaleContext, previousAttributes); //为什么要恢复?怕影响Servlet外面的filter工作,可能有什么修改需要恢复?
publishRequestHandledEvent
配置:web.xml中配置springmvc servlet时配置,默认true。
用法:可以用来记录日志。
DispatcherServlet
初始化各种组件init()
- MutipartResolver
- LocaleResolver
- ThemeResolver
- HandlerMappings
- HandlerAdapters
- HandlerExceptionResolvers
- RequestToViewNameTranslator
- ViewResolvers
- FlashMapManager
doService()
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + requestUri + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
//判断是否是include请求,如果是则对request做快照备份,结束后还原
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
//设置属性
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
//后面3个和flashMap有关。用于redirect传递参数。
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
//先取出flashmap放入INPUT_FLASH_MAP_ATTRIBUTE,再放入model中。在Controller中可以使用。
//RedirectAttributes.addFlashAttribute() 将参数添加到session中
//RedirectAttributes.addAttribute() 将参数拼接到url后。
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
- 设置request一些属性
- 处理include请求快照
- doDispatch()
doDispatch()
根据request找handler
根据handler找HandlerAdapter
用Adapter处理handler
processDispathResult() 处理结果,包括找到view并渲染。
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 { //判断是否是Multipart 请求,用到MultipartResolver processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. //根据request获取handler,用到handlerMapping mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. //获取adatper HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } }
//interceptor#perHandler if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { //异步处理,则直接返回 if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); //interceptor#postHandler mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
//用到HanlderExceptionResolver
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//渲染页面,用到themeResolver
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
//异步
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
//触发Interceptor#afterCompletion()
mappedHandler.triggerAfterCompletion(request, response, null);
}
}