Springmvc源码分析之dispatcherServlet
程序员文章站
2024-02-08 14:46:16
...
1调用流程
从Servlet的分析思路来分析dispatcherServlet。我们都知道serlvet主要分为init(),doget(),doPost(),destory()等方法,dispatcherServlet也是按这个流程进行操作的。
- 首先Tomcat启动之后,会读取web.xml文件对dispatcherServlet实例化,同时它的抽象父类也会实例化,子类重写的方法覆盖父类的方法(这种方式在servlet使用非常多)。通过web.xml的映射条件,对应的请求会交给dispatcerServlet处理。
- 调用init()方法初始化工作。
- 调用doget()和dopost()实现业务操,最终由dispatcerServlet的dodispach()函数完成拦截器,handlermapping和handleradapter,handler执行返回model and view,视图渲染等真正的业务操作。
2源码分析
2.1DispatcherServlet继承结构图
2.2初始化工作
- HttpServletBean的init()方法
init方法被HttpServletBean类重写,会覆盖父类的同名方法,所以我们从这个方法开始分析。
@Override
public final void init() throws ServletException {
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
//这个方法已经被子类FrameworkServlet方法覆盖
initServletBean();
}
-
FrameworkServlet的initServletBean()
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
//调用此方法,初始化WebApplicationContext容器
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
if (logger.isDebugEnabled()) {
String value = this.enableLoggingRequestDetails ?
"shown which may lead to unsafe logging of potentially sensitive data" :
"masked to prevent unsafe logging of potentially sensitive data";
logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
"': request parameters and headers will be " + value);
}
if (logger.isInfoEnabled()) {
logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}
- FrameworkServlet的initWebApplicationContext
protected WebApplicationContext initWebApplicationContext() {
//读取web.xml的配置信息,初始化得到一个WebApplicationContext的根容器
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) {
//设置父容器
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
//web容器的基本操作
if (wac == null) {
wac = findWebApplicationContext();
}
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//同步保护 调用onRefresh方法实现dispatcherServlet的一些配置工作,该方法已经被子类覆盖
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
- dispatcherServlet的onRefresh()方法
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
//springmvc一系列解析器的的初始化工作
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
- 以initHandlerMappings为例(其他解析器初始化原理基本类似都是从applicationContext容器中注入相应的对象)
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//默认查找所有的handlerMapping
if (this.detectAllHandlerMappings) {
//从applicationContext中找到所有的handlerMappings,包括他们的父类
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
//得到一个handlerMappings的数组列表,在请求映射的时候,会用到该数组的信息。
this.handlerMappings = new ArrayList<>(matchingBeans.values());
//数组排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
//否则通过beanName从容器中注入一个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) {
//如果没有配置handlermapping会默认配置一个handlermaping
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
2.3 请求处理
根据Servlet的请求方式,最终会被发送到doGet()和doPost()方法中,这两个方法被子类FrameworkServlet所覆盖,所以从此开始。
-
FrameworkServlet的doGet()和doPost()方法会转到processRequest()
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
// 返回与当前线程相关联的 LocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//绑定请求参数
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
//此方法被子类覆盖,调用方法处理请求
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
//重置 LocaleContext等Context信息
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
- 调用doService()方法
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
//设置一些参数绑定
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());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
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 {
//最终调用该方法实现springmvc的真正操作
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
本文介绍从dispatcherServlet的初始化到doDispatch()方法之前的主要过程,可以帮助我们认识springmvc的初始化的流程和基本原理。预知doDispatch()详情,请阅读下期。
推荐阅读
-
Springmvc源码分析之dispatcherServlet
-
SpringMVC之RequestContextHolder分析
-
SpringMVC 4.3 源码分析之 HandlerExceptionResolver
-
SpringMVC组件之HandlerMapping分析
-
jQuery源码分析之jQuery中的循环技巧详解
-
JVM源码分析之安全点safepoint 博客分类: JVM
-
JVM源码分析之安全点safepoint 博客分类: JVM
-
MongoDB源码阅读之Shard源码分析--CongfigServer启动
-
Django框架之DRF 认证组件源码分析、权限组件源码分析
-
Netty源码分析 (十二)----- 心跳服务之 IdleStateHandler 源码分析