您的位置:首页 > 编程语言 > Java开发

[SpringMVC源码剖析] 前奏:梦开始的地方

2017-11-03 15:59 337 查看

SpringMVC源码剖析

纵览:SpringMVC处理请求

本节作为SpringMVC源码剖析的基本,主要介绍以下三方面内容。

1.核心DispatcherServlet的加载方式

2.DispatcherServlet初始化过程

3.SpringMVC接收请求并作出响应(粗粒度)

1.核心DispatcherServlet的加载方式

1.1 传统的JavaWeb工程,以web.xml来配置加载Servlet容器的上下文,这显然有些麻烦。

1.2 自从Servlet3.0+的出现,Spring-web模块提供了一种免配置文件,在如Tomcat(支持Servlet3.0+)这样的Servlet容器启动时,自动调用了实现的WebApplicationInitializer(全路径org.springframework.web.WebApplicationInitializer)接口的类的onStartup方法,并将容器的ServletContext往下传递。

public interface WebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}


1.3 从Spring-web模块的API中,找到子类AbstractAnnotationConfigDispatcherServletInitializer,它间接实现了WebApplicationInitializer接口,父类onStartup方法,首先创建RootWebApplicationContext并设置ContextLoaderListner监听器;其次,注册往servletContext注册DispatcherServlet实例。

public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);

registerDispatcherServlet(servletContext);
}
protected void registerDispatcherServlet(ServletContext servletContext) {
//此处往servletContext添加DispatcherServlet实例
//并为DispatcherServlet添加过滤器
}


1.4 由于AbstractAnnotationConfigDispatcherServletInitializer是抽象类,Spring容器不能注入。它重写了父类创建根ApplicationContext与ServletApplicationContext方法,并抽象出两个方法(用来创建根ApplicationContext和ServletApplicationContext容器时,需要注入的组件字类节数组)。

public abstract class AbstractAnnotationConfigDispatcherServletInitializer
extends AbstractDispatcherServletInitializer {

@Override
protected WebApplicationContext createRootApplicationContext() {
...
}
@Override
protected WebApplicationContext createServletApplicationContext() {
...
}
//用来创建根ApplicationContext和ServletApplicationContext容器时,需要注入的组件字类节数组
protected abstract Class<?>[] getRootConfigClasses();
protected abstract Class<?>[] getServletConfigClasses();

}


1.5 因此 我们只需要编写SpringMVCInitializer来继承AbstractAnnotationConfigDispatcherServletInitializer类,让它来帮我们完成对DispatcherServlet实例的加载即可。

2.DispatcherServlet初始化过程

2.1 DispatcherServlet有个静态块,用于加载同包下DispatcherServlet.properties策略文件的内容,代码如下

static {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}


DispatcherServlet.properties 策略文件的内容

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager


2.2 DispatcherServlet作为一个HttpServlet类,在加载时,会调用init方法,查找或创建WebApplication容器并刷新操作(如果使用WebApplicationInitilazer加载方式,RootWebApplicationContext是已经存在了)

public abstract class HttpServletBean extends HttpServlet
implements EnvironmentCapable, EnvironmentAware {

@Override
public final void init() throws ServletException {
initServletBean();
}


public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

@Override
protected final void initServletBean() throws ServletException {

this.webApplicationContext = initWebApplicationContext();

}

protected WebApplicationContext initWebApplicationContext() {
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()) {
...
//刷新,调用cwac.refresh()方法
//触发了ContextRefreshListener.onApplicationEvent方法
//调用FrameworkServlet.this.onApplicationEvent方法
//调用子类,即DispatcherServlet.onRefresh方法
configureAndRefreshWebApplicationContext(cwac);
}
}
}
...

return wac;
}

public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
onRefresh(event.getApplicationContext());
}

protected void onRefresh(ApplicationContext context) {
// 调用子类,即DispatcherServlet.onRefresh方法
}

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
}


2.3 调用DispatcherServlet.onRefresh方法,

@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
//判断Spring容器是否存在MultipartResolver,LocaleResolver,ThemeResolver,不存在打印日志
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
//默认行为,加载容器的hadlerMappings,handlerAdapters,handlerExceptionResolvers,并排序
//不存在则加载策略文件
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
//容器中加载名为viewNameTranslator的解析器,
//如果找不到,从策略文件加载第一个Translator,即
//org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
initRequestToViewNameTranslator(context);
/默认行为,加载容器的viewResolvers,并排序
//不存在则加载策略文件
initViewResolvers(context);
//容器中加载名为flashMapManager,
//不存在的话,同上处理,找策略文件中第一个
initFlashMapManager(context);
}


3.SpringMVC接收请求并作出响应(粗粒度)

3.1 DispatcherServlet作为httpServlet,当接收到请求时,会调用doService方法

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//往request设置setAttribute,将当前环境(本地化解析器,主题解析器等)给request,方法mvc框架其他组件可以获取到。
...
try {
//真实调用
doDispatch(request, response);
}
finally {
//为request设置WebAsyncManager属性
//如果是同步请求,恢复请求前的属性
...
}
}


3.2 DispatcherServlet的doDistpach方法,才是接收请求的核心方法

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 {
//判断request头部ContentType是否以"multipart/"开头,来标记是否为附件上传
processedRequest = checkMultipart(request);
//是否附件请求标记
multipartRequestParsed = (processedRequest != request);

//
// 从handlerMappings(RequestMappingHanderMapping,策略文件的handlerMapping类已经过时了),获取HandlerExecutionChain
//HandlerExecutionChain(包含一个handlerMethod,以及一堆handlerInterceptor)
mappedHandler = getHandler(processedRequest);
//找不到handlerMethod时,根据标是否抛出异常,还是直接response.sendError
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}

// 根据handerMethod找到HandlerAdapter(RequestMappingHandlerAdapter)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 修改 last-modified 头部,如果支持的话.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 调用所有HandlerInterceptor的preHandle()方法,如果返回false,不处理请求
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// 核心:::::通过RequestMappingHandlerAdapter的handle方法,处理请求逻辑,返回ModelView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//从viewNameTranslator中获取默认视图名,并设置到mv中
applyDefaultViewName(request, mv);
//调用所有HandlerInterceptor的postHandle()方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//渲染请求结果
//从ModelView中获取View
//view.render(model,req,resp)渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//调用handerExecutionChain的afterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
//调用handerExecutionChain的afterCompletion
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// 调用handerExecutionChain的applyAfterConcurrentHandlingStarted,实现异步拦截
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 如果为附件请求,清理现场
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}


注:从DispatcherServlet.properties知道默认的HandlerMapping实现类已经注解了@Deprecated,从注释头部得知,建议使用RequestMappingHandlerMapping类。Spring-Webmvc模块中,提供了@EnableWebMvc,它导入了@Import(DelegatingWebMvcConfiguration.class)DelegatingWebMvcConfiguration类,而DelegatingWebMvcConfiguration类继承了WebMvcConfigurationSupport,WebMvcConfigurationSupport又注入了RequestMappingHandlerMapping实例,如下面代码。所以可以通过注解@EnableWebMvc,向容器注入RequestMappingHandlerMapping实例。

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors());
//注入内容协商管理器handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());

PathMatchConfigurer configurer = getPathMatchConfigurer();
if (configurer.isUseSuffixPatternMatch() != null) {
handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch());
}
if (configurer.isUseRegisteredSuffixPatternMatch() != null) {
handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch());
}
if (configurer.isUseTrailingSlashMatch() != null) {
handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch());
}
if (configurer.getPathMatcher() != null) {
handlerMapping.setPathMatcher(configurer.getPathMatcher());
}
if (configurer.getUrlPathHelper() != null) {
handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper());
}

return handlerMapping;
}


注:RequestMappingHandlerMapping间接实现了InitializingBean接口,重写afterPropertiesSet,代码如下

@Override
public void afterPropertiesSet() {
if (this.useRegisteredSuffixPatternMatch) {
this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
}
//调用父类
super.afterPropertiesSet();
}


@Override
public void afterPropertiesSet() {
initHandlerMethods();//初始化handlerMethods
}
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}

String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
//收集所有注解了@Controller或@RequestMapping的方法
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
isHandler(getApplicationContext().getType(beanName))){
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}


下节将细化介绍DispatcherServlet的getHandler(HttpServletRequest request)方法为入口进行源码剖析,将了解到

如何获取到handlerMethod

如何获取handlerInterceptor

如何创建handlerExecutionChain
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: