一、Spring_mvc的架构原理
1.首先用户通过url来提交request查询。
2.控制器(前端控制器,DispatcherServlet)收到rquest数据后因为无法直接通过url获取到直接的处理器于是将url交由到处理器映射器去查找处理器。(为了拓展)
3.处理器映射器返回给控制器一个处理器。
4.由于处理器有多个,管理起来很是麻烦于是通过一个处理器适配器可以完成对于不同的处理器的处理(这里的适配器相当于一个工厂用来生产不同的处理器)于是控制器向处理器适配器发送一个请求处理器适配器执行处理器的要求(为了拓展性)。
5.处理器适配器收到命令后调用相关的处理器执行处理器。
6.处理器返回一个modelandview给处理器适配器。
7.处理器适配器返回一个modelview给控制器。这个时候控制器就拿到了模型(数据)和要渲染的view(视图渲染器)。
8.由于view和处理器一样会有多个,为了拓展性,于是会有一个视图适配器(相当于一个视图工厂),去处理单独的视图。
9.视图适配器给控制器返回一个视图渲染器(比如jsp,html,pdf…)。
10.控制器拿到视图渲染器后就会将model里的数据填充到response中去。
11.控制器给用户返回一个request响应。
二、源码跟踪
从上面可以知道大部分的模块都要和控制器进行交互,于是代码的如可也是从控制器开始即DispatchServlet开始。
首先是代码的准备:
//handler实现类
<bean id="hellocontrollerid" name="/welcome.html" class="test.contrller.HelloCntroller"></bean>
//处理器适配器
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
//处理器映射器
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/welcome1.html">hellocontrollerid</prop>
</props>
</property>
</bean>
//视图解析
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--定位jsp的位置-->
<property name="prefix" value="WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import test.contrller.po.Items;
import java.util.ArrayList;
//实现了Controller接口
public class HelloCntroller implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//调用service查找 数据库,查询商品列表,这里使用静态数据模拟
ArrayList<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList);
//指定视图
modelAndView.setViewName("itemsList");
return modelAndView;
}
}
使用过Spring的都知道在Spring中真正干活的是以do开头的函数比如:docreate、dolocationbean。。。
org.springframework.web.servlet.DispatcherServlet`
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//得到request
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//得到处理器映射器
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//mappedHandler.getHandler()得到具体的handler
//交由处理器适配器去执行相应的handler
//原因是如果不这样那么代码将会相当的凌乱,难以管理,这个也符合Spring的
//代码分割,以小化大
HandlerAdapter ha = this.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 (this.logger.isDebugEnabled()) {
this.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;
}
//处理器适配器执行相关的处理器,z自己实现的继承了controller的类(handler)
mv = ha.***handle***(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//得到具体的视图名
this.**applyDefaultViewName**(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//得到真正视图,填充response域
this.***processDispatchResult***(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}```
//执行handler
SimpleControllerHandlerAdapter{
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//由于强转了为Controller于是就可以直接调用到自己实现的handler,即
//HelloCntroller
return ((**Controller**)handler).handleRequest(request, response);
}
}
//得到视图名
private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
//将得到视图名存储在modelAndview中。
mv.setViewName(this.**getDefaultViewName**(request));
}
}
protected String **getDefaultViewName**(HttpServletRequest request) throws Exception {
//使用了委派模式,这里不是实现方法
return this.viewNameTranslator.**getViewName**(request);
}
//执行真正地方
public String **getViewName**(HttpServletRequest request) {
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
//prefix :<property name="prefix" value="WEB-INF/jsp/"/>
//suffix:<property name="suffix" value=".jsp"/>
//lookupPath在 HelloController写进去的listitems
return this.prefix + this.transformPath(lookupPath) + this.suffix;
}
DispatcherServlet.
private void **processDispatchResult**(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
.........
if (mv != null && !mv.wasCleared()) {
//使用了委派模式,具体的是实在其他地方
this.**render**(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
}
...........
}
}
protected void **render**(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
view = this.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 '" + this.getServletName() + "'");
}
} else {
//得到具体的视图
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.**render**(mv.getModelInternal(), request, response);
} catch (Exception var7) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var7);
}
throw var7;
}
}
package org.springframework.web.servlet.view;
public abstract class AbstractView extends WebApplicationObjectSupport implements View, BeanNameAware {
public void **render**(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view with name '" + this.beanName + "' with model " + model + " and static attributes " + this.staticAttributes);
}
Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);
//具体的实现,response的填充
this.**prepareResponse**(request, response);
this.**renderMergedOutputModel**(mergedModel, this.getRequestToExpose(request), response);
}
}
至此代码跟踪结束。
总结
Spring_mvc延续了Spring的代码风格–小块小块的积累成大块,能分割就分割充分体现了其解耦的能力。
Spring_mvc的架构也是这样使用控制器来处理各个模块之间的交互。
这样也减少了其他各个模块之间的耦合性,使得架构更容易扩展。