spring作为java开发最常用的框架之一,主要优势在与可以很容易的与第三方框架整合,在早起的web开发环境中常用的组合
是SSH即 struts+ spring + Hibernate,后来演变为SSM 即struts + spring + Mybatis,后来spring推出springMVC模块,
来完成web项目的开发,因为spring官方的支持使得在与spring进行整合的时候异常简单,而且在使用的时候也比struts方便,所以
越来越多的的项目使用springMVC替换struts,下面就springMVC的源码做一下简单的分析
一:主要概念
HandlerAdapter:根据Handler来找到支持它的 HandlerAdapter,通过HandlerAdapter执行这个Handler
得到 ModelAndView 对象
handler:具体的请求处理方法包含类及方法
handlerMapping:我们在controller的方法是添加的requestMapping信息,在容器启动的时候,通过容器扫描生成
RequestMappingInfo信息,里面包括请求的方法方式参数及参数的顺序等信息放入handlerMapping中,
可以通过handerMapping 获取hander
二 :springMVC的启动
作为一个传统的web项目,Servlet容器的启动是已web.xml文件中的配置为基础的,在springMVC项目的web.xml文件中
通常会配置一个dispatcherServlet对所有的请求做转发处理 DispatcherServlet的继承关系如下
项目在spring容器启动后根据web.xml文件的配置启动DispatcherServlet的初始化调用的是HttpServletBean中的init方法,
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// 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();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
在FrameworkServlet的initServletBean方法中先看 this.webApplicationContext = initWebApplicationContext() 这行代码 我们来看下initWebApplicationContext() 方法
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//WebApplicationContext 因为实现了ApplicationContextAware接口 会在容器启动后注入spring的上下文applicationContext
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
//设定当前MVC容器的父容器
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
wac = findWebApplicationContext();
}
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//刷新容器 由子类DispatcherServlet实现只有一行代码 initStrategies(context);
onRefresh(wac);
}
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
在DispatcherServlet的onRefresh方法中只有一行代码 initStrategies(context) ,在此方法中完成springMVC中九大组件的注册
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);//用于处理上传请求
initLocaleResolver(context);
initThemeResolver(context);//主题解析器
initHandlerMappings(context);//handlerMapping 解析器
initHandlerAdapters(context);//handler解析具体的方法
initHandlerExceptionResolvers(context);//异常解析
initRequestToViewNameTranslator(context);//请求到视图的解析
initViewResolvers(context);//视图解析器
initFlashMapManager(context);// 用来管理FlashMap的,FlashMap主要用在redirect中传递参数
}
至此 springMVC容器的启动完成
三:请求响应
在客户端发送http请求时会被DispatcherServlet中的doService方法拦截,在doService方法中完成请求上下文的
参数处理后调用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 {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否为上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//更具request处理链 拦截器过以及具体的处理方法
mappedHandler = getHandler(processedRequest);
//url 未找到处理请求的handler的处理
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}.
HandlerAdapter ha = 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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//拦截器中的preHandle不通过是的处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//通过反射执行具体的请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//视图
applyDefaultViewName(processedRequest, mv);
//执行拦截器中的 postHandle不通过是的处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}finally {
//释放资源
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
至此请求处理完成
`