springMVC分析-1
MVC
作为一个MVC框架,必须回答一下几个问题
- 请求映射到控制器
- 请求数据进行绑定
- 视图渲染
而spring mvc是如何解决这几个问题的呢?
首先,从DispatcherServlet这个入口开始分析,DispatcherServlet继承于FrameworkServlet,而FrameworkServlet继承HttpServletBean,HttpServletBean又继承与HttpServlet,先从
HttpServletBean的init方法开始分析
@Override
public final void init() throws ServletException {
//省略
// Let subclasses do whatever initialization they like.
initServletBean();//这是个空方法,可以给其子类进行重写
}
再从其子类FrameworkServlet重写的initServletBean()方法
@Override
protected final void initServletBean() throws ServletException {
//日志块省略
try {
//初始化springMvc的ApplicationContext、并查找是否有spring的ApplicationContext 并将其设置为root applicationContext ,初始化spring mvc的bean
this.webApplicationContext = initWebApplicationContext();
//空方法,可扩展
initFrameworkServlet();
}
//catch块,日志省略
}
继续分析DispatcherServlet init()方法
protected void initStrategies(ApplicationContext context) {
//初始化处理mine为multipart/form-data的处理器
initMultipartResolver(context);
//初始化本地化处理器,默认是以用户的http请求的AcceptHeaderLocaleResolver
initLocaleResolver(context);
//初始化主题处理器
initThemeResolver(context);
//初始化HandlerMappings
initHandlerMappings(context);
//初始化处理器适配器
initHandlerAdapters(context);
//处理异常处理器
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
//处理视图转换
initViewResolvers(context);
initFlashMapManager(context);
}
从上面代码可以看出来,DispatcherServlet会初始化一些处理器,再分析其处理请求的方法
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/form-data
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 将请求映射到具体的处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
对处理器进行适配
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()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
拦截器处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用具体的控制器进行处理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
拦截器处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//处理异常、渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
//省略
}
上述代码包括了请求到响应 spring做的过程。我们来细化分析一下。
首先我们来分析请求映射到逻辑处理器的过程
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
从这段代码看,其会遍历所有的HandlerMapping,然后获取一个HandlerExecutionChain执行对象,而入参是HttpServletRequest,意味着这个HandlerMapping可以根据http请求的所有信息获取到一个控制器。这是第一个扩展点,我们可以实现一个HandlerMapping来处理请求映射。再看HandlerExecutionChain这个类
public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;
}
这个类最重要的两个属性,可以看出其对执行对象里面包含了两个部分,一个是控制器,另一个则是拦截器数组,这是第二个扩展点,我们可以实现HandlerInterceptor,在控制器处理前后进行一些操作。
我们来这个操作,其会获取一个控制器的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
}
从这个方法的执行,我们可以看出来其依旧是遍历handlerAdapters后返回第一个HandlerAdapter进行处理Handler,所以我们可以实现HandlerAdapter这个接口,自定义对Handler进行处理,这是第三个扩展点
继续玩下走,在processDispatchResult()方法中,先判断是否有exception,若有且不是ModelAndViewDefiningException,则交给HandlerExceptionResolver处理,HandlerExceptionResolver是个接口,可以看出这是第四个扩展点。继续往下走,到render()方法,
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
// 判断View是不是字符串
if (mv.isReference()) {
//交给ViewResolvers处理,将其转换成View对象
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
//将数据渲染到视图中
try {
view.render(mv.getModelInternal(), request, response);
}
}
至此springMVC从请求到响应的流程结束,可以看出springMVC玩的是开闭原则,对修改关闭,可扩展。这是个大体流程,下一篇文章将分析其细节化