SpringMvc源码分析
一、Mvc模式解读
Model1 模型
jsp和javaBean两部分组成,jsp既要展示数据又要处理数据(也就是同时干了控制器和视图的事情)
Model2
它是mvc模型的一个经典应用,处理请求和展示数据进行分离,提高了代码的可重复性与易维护性
二、SpringMvc执行流程图解
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
三、底层源码剖析
1.doService()
//精简版-代码不全,只为方便理解流程
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
doDispatch(request, response);
}
finally {
//……
}
}
2.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);
// 获得处理器执行链对象HandlerExecutionChain mappedHandler
mappedHandler = getHandler(processedRequest);
// 通过处理器获取对应的处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 适配器调用控制器中的方法,返回ModelAndView对象.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//应用默认的视图名字
applyDefaultViewName(processedRequest, mv);
//应用相应的拦截器的方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
//……
}
//进行结果的解析
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
finally {
//……
}
}
3.getHandler()
//获得处理器执行链对象(包含处理器和拦截器)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
//遍历HandlerMapping处理器映射器的list集合,拿到对应的对象
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
4.getHandlerAdapter()
//获取处理器适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
//遍历处理器适配器的list集合,找到对应的适配器
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {//是否支持
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
5.handle()
//HandlerAdapter.handle() 接口
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//AbstractHandlerMethodAdapter.handle() 抽象类
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
//RequestMappingHandlerAdapter.handleInternal() 具体的实现——注解一般使用这个适配器
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
6.processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
if (mv != null && !mv.wasCleared()) {
//渲染结果
render(mv, request, response);
}
}
7.render()
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName(); //获取view视图名字
if (viewName != null) {
// 视图解析,返回具体的view对象
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
}
else {
view = mv.getView();
}
try {
//mv.getModelInternal()其实就是model数据
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
throw ex;
}
}
四、控制器不同实现方式与底层源码剖析
1.方式一:实现Controller接口
public class Test01 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("Controller接口 ..............");
return null;
}
}
2.方式二:实现HttpRequestHandler接口
public class Test02 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
System.out.println("HttpRequestHandler.........");
}
}
3.方式三:使用@Controller注解
@Controller
public class Test03 {
@RequestMapping("/test03")
public void test03(){
System.out.println("Controller注解 ......");
}
}
三种不同的实现方式,对应不同的处理器与适配器,因此的handle方法也会有区别
五、参数注入解密
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
Object arg = null;
if (arg == null) {
//开始获取参数
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
return arg;
}
① 通过注解进行绑定 @RequestParam
② 通过参数名称进行绑定. 使用注解进行绑定,我们只要在方法参数前面声明@RequestParam("a"),就可以将request中参数a的值绑定到方法的该参数上。使用参数名称进行绑定的前提是必须要获取方法中参数的名称,Java反射只提供了获取方法的参数的类型,并没有提供获取参数名称的方法。SpringMVC解决这个问题的方法是用asm框架读取字节码文件,来获取方法的参数名称。
六、Spring与Springmvc容器关系
spring是一个一站式的轻量级的java开发框架,核心是控制反转(IOC)和面向切面(AOP),针对于开发的WEB层(springMvc)、业务层(Ioc)、持久层(jdbcTemplate)等都提供了多种配置解决方案;
springMvc是spring基础之上的一个MVC框架,主要处理web开发的路径映射和视图渲染,属于spring框架中WEB层开发的一部分;
父子容器
子容器(SpringMVC容器)可以访问父容器(Spring容器)的Bean,父容器(Spring容器)不能访问子容器(SpringMVC容器)的Bean。也就是说,当在SpringMVC容器中getBean时,如果在自己的容器中找不到对应的bean,则会去父容器中去找,这也解释了为什么由SpringMVC容器创建的Controller可以获取到Spring容器创建的Service组件的原因