spring底层运行原理+源码解析
springmvc运行原理图:(重点)
一、创建springmvc-demo3
1、IDEA搭建WEB工程
2、web包下创建 WEB-INF 包,并在其之下创建 lib 包并导入 springmvc 开发 jar 包
3、WEB-INF 包下创建web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!--配置DispatcherServlet->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--拦截所有>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4、在src下创建springmvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="com.atguigu.springmvc">
</context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
5、修改index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="helloworld">Hello World</a>
</body>
</html>
6、创建HelloWorld的controller,注意创建在com.atguigu.springmvc包路径下,因为,之前的springmvc.xml文件中便表明了包的扫描路径
7、因为springmvc.xml中设置了视图解析器,所以应该在 WEB-INF 的包路径下创建一个views包来存放 jsp 页面,创建success页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>Success Page</h4>
</body>
</html>
8、运行之后
二、源码分析
1、第一个流程,即如上代码运行流程(没有配置<mvc:default-servlet-handler/>
)
因为没有配置<mvc:default-servlet-handler/>
所以一旦请求地址没有映射,那么就会报如下问题
2、第二个流程,配置了<mvc:default-servlet-handler/>
(1)、编写abc.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>Httml Page</h4>
</body>
</html>
(2)springmvc.xml配置<mvc:default-servlet-handler/>
<mvc:default-servlet-handler/>
结果:
3、第三个流程,如果有对应映射呢?(重点)
代码不改,出现bug
解决:
添加了<mvc:default-servlet-handler/>
后必须同时在其后边添加 <mvc:annotation-driven></mvc:annotation-driven>
,不然RequestMapping不起作用。
Debug源码解析
1、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 {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//1
//获取处理器调用件HandlerExecutionChain,该类包含了处理器对象以及和处理器相关 的拦截器,因为调用处理器之前应该调用拦截器的方法,而这个类提供了这些
//那么这个方法是如何获取mappedHandler 的呢?请看下方的getHandle方法
//如果发的请求是没有经过映射的,那么mappedHandler 也不为空,因为之前我在
//springmvc.xml中配置了<mvc:default-servlet-handler/>和<mvc:annotation-driven></mvc:annotation-driven>
//如果没有配置这两个节点,那么就会返回空,如果为空,那么就会直接return,返回404,
//原因是什么??请看下一个方块“添加default-servlet-handler和annotation-driven之后的区别”
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//3
//获取适配器
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()) {
String requestUri = urlPathHelper.getRequestUri(request);
this.logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
//4
//调用拦截器的PreHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
//5
//调用目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
this.applyDefaultViewName(request, mv);
//6
//调用拦截器的PostHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var28) {
dispatchException = var28;
}
//7
//处理视图,具体方法看下方的processDispatchResult方法
this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception var29) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var29);
} catch (Error var30) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var30);
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
} else {
if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
}
//2
//getHandler方法,其实是使用handlerMapping来获取HandlerExecutionChain 的,即handle的映射
//handlerMapping这个对象定义了请求到处理器之间的映射
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Iterator var2 = this.handlerMappings.iterator();
HandlerExecutionChain handler;
do {
if (!var2.hasNext()) {
return null;
}
HandlerMapping hm = (HandlerMapping)var2.next();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
handler = hm.getHandler(request);
} while(handler == null);
return handler;
}
//8
//处理视图方法processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {//9、异常处理
if (exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
//如果发生异常就调用processHandlerException方法,具体方法在下方
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if (mv != null && !mv.wasCleared()) {
//11、渲染视图,如何渲染?代码render在下方
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");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
//19、调用拦截器的AfterCompletion,这是最后一步
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
//10
//处理异常
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
ModelAndView exMv = null;
//靠调用异常解析器handlerExceptionResolvers来处理
Iterator var6 = this.handlerExceptionResolvers.iterator();
while(var6.hasNext()) {
HandlerExceptionResolver handlerExceptionResolver = (HandlerExceptionResolver)var6.next();
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
return null;
} else {
if (!exMv.hasView()) {
exMv.setViewName(this.getDefaultViewName(request));
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, this.getServletName());
return exMv;
}
} else {
throw ex;
}
}
//12
//渲染视图的方法
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()) {
//13、
//找到view对象,方法resolveViewName在下方
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 {
//15,真正渲染视图的方法,应该去view.class中然后找到rendce的实现类AbstractView类,操作如下面方块“AbjectView类所在地”
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;
}
}
//14、resolveViewName方法,寻找合适的视图解析器
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
Iterator var5 = this.viewResolvers.iterator();
//遍历viewResolvers,寻找合适的视图解析器
View view;
do {
if (!var5.hasNext()) {
return null;
}
ViewResolver viewResolver = (ViewResolver)var5.next();
view = viewResolver.resolveViewName(viewName, locale);
} while(view == null);
return view;
}
//AbstractView类中render方法
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);
this.prepareResponse(request, response);
//16、找到InternalResourceView实现类,地址在下方方块“renderMergedOutputModel实现类InternalResourceView所在地”中,代码如下
this.renderMergedOutputModel(mergedModel, request, response);
}
//17、InternalResourceView的实现类
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest requestToExpose = this.getRequestToExpose(request);
this.exposeModelAsRequestAttributes(model, requestToExpose);
this.exposeHelpers(requestToExpose);
String dispatcherPath = this.prepareForRendering(requestToExpose, response);
RequestDispatcher rd = this.getRequestDispatcher(requestToExpose, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + this.getUrl() + "]: Check that the corresponding file exists within your web application archive!");
} else {
if (this.useInclude(requestToExpose, response)) {
response.setContentType(this.getContentType());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Including resource [" + this.getUrl() + "] in InternalResourceView '" + this.getBeanName() + "'");
}
rd.include(requestToExpose, response);
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Forwarding to resource [" + this.getUrl() + "] in InternalResourceView '" + this.getBeanName() + "'");
}
//18、转发
rd.forward(requestToExpose, response);
}
}
}
添加default-servlet-handler和annotation-driven之后的区别
没有添加<mvc:default-servlet-handler/> <mvc:annotation-driven></mvc:annotation-driven>
之前
在运行到mappedHandler = this.getHandler(processedRequest);
的时候,只能找到如下红框中的HandleMapping。在getHandler方法中就会返回null,最后就会返回404页面。
如果加上这两个节点又会怎么样?
那么返回值不为空,加上这两个节点后就会出现下图红框中的三个HandleMapping
其中RequestMappingHandleMapping是搞requestMapping的映射的
SimpleUrlHandleMapping是搞静态请求的,如上当进行到mappedHandler = this.getHandler(processedRequest);
的时候,会遍历红框中的HandleMapping,上两个HanddleMapping都会返回空,因为原来的请求没有映射,但是到SimpleUrlHandleMapping不会,因为将其默认为了静态资源请求。
如果请求有映射,那么
AbstractView类所在地
renderMergedOutputModel实现类InternalResourceView所在地
断点实现一遍图
即是解析视图内容返回视图
debug页面