Spring mvc
1. DispatcherServlet(前端控制器)
负责拦截所有的URL 并分发给其他组件
2. HandlerMapping(处理器映射器)
处理映射器通过URL 找到相应的处理器
3. Handler(处理器)
处理器调用Service 层
4. HandlerAdapter(处理器适配器)
处理器适配器负责根据特定的规则对处理器进行执行,它可以**执行多种类型的处理器**
5. ViewResolver(视图解析器)
viewResolver 可以将处理结果生成View(视图)并展示给用户
6. View:视图
MVC 流程
<servlet>
<servlet-name>Dispatch</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Dispatch</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 包扫喵-->
<context:component-scan base-package="top.spacexist"/>
<!-- 开启注解驱动-->
<mvc:annotation-driven/>
<!-- 释放静态资源 css-->
<mvc:default-servlet-handler/>
<mvc:interceptors>
<bean class="top.spacexist.interceptor.testInterceptor"></bean>
</mvc:interceptors>
</beans>
-
客户端发出一个HTTP请求,Web应用服务器接收这个请求,如果Web应用的配置文件中指定有DispatcherServlet的映射路径,那么服务器将该请求交给DispatchserServlet处理。
-
DispatchserServlet接收到请求后,将根据包括URL、方法、报文头和参数在内的请求信息以及HandlerMapping的配置解析出目标Handler
-
在解析出目标Handler后,DispatchserServlet将通过相应的HandlerAdapter来调用Handler并完成业务逻辑的处理。
-
在成业务逻辑处理后,代表处理结果的ModelAndView会被返回到DispatchserServlet,ModelAndView中包含逻辑视图名和模型数据信息。
-
DispatcherServlet通过ViewResolver完成逻辑视图名到真实View对象的解析。
-
获得真实的View对象后,DispatcherServlet将模型数据传给View对象并通过View对象对模型数据进行视图渲染
-
DispatcherServlet将最终的View对象响应给客户端并展示给用户。
-
mappedHandler = getHandler(processedRequest);
//进入DistpatchServlet 调用这个方法
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}//如果没有对应mapper 就返回NOFOUND
//mappedHandler = {HandlerExecutionChain@5825} "HandlerExecutionChain with [top.spacexist.hello#hello(String)] and 2 interceptors"
//handler = {HandlerMethod@5513} "top.spacexist.hello#hello(String)"
//interceptorList = {ArrayList@5826} size = 2
//interceptorIndex = -1 // 和Chain 中内容一样
// Determine handler adapter for the current request. 现在开始寻找处理适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {//判断ISget
//lastModifed = -1;
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return; // to4
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//实际调用handler 从这里开始
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// to 6
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv); //应用后置拦截器 to 8
private List<HandlerMapping> handlerMappings; //处理器映射为Array
private List<HandlerAdapter> handlerAdapters; //处理器适配器
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
//匹配当前request 所对应的hander
if (handler != null) {
return handler; //return 了一个 HanderExecutionChain
类型的hander
}
}
}
return null;
}
//hander : top.spacexist.hello#hello(String); top.spacexist.hello 为handler
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);javadoc
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//第一步判断 是否为Handler 强制转换为HanderExecutionChain
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 匹配拦截器 如果匹配上了 就丢入Chain中
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
// Chain 主要有那些呢?
chain = {HandlerExecutionChain@5825} "HandlerExecutionChain with [top.spacexist.hello#hello(String)] and 0 interceptors"
handler = {HandlerMethod@5513} "top.spacexist.hello#hello(String)"
interceptorList = {ArrayList@5826} size = 0
interceptorIndex = -1
目前 有这三个值两Handler 和 Interceptor 为ArrayList 类型
private List<HandlerAdapter> handlerAdapters;
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
// 4
public boolean checkNotModified(long lastModifiedTimestamp) {
return checkNotModified(null, lastModifiedTimestamp);
}
public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestamp) {
HttpServletResponse response = getResponse();
if (this.notModified /*-1*/ || (response != null && HttpStatus.OK.value() != response.getStatus())) {
return this.notModified;
}
//判断是不是为OK
if (response != null) {
boolean isHttpGetOrHead = SAFE_METHODS.contains(getRequest().getMethod());
if (this.notModified) {
response.setStatus(isHttpGetOrHead ?
HttpStatus.NOT_MODIFIED.value() : HttpStatus.PRECONDITION_FAILED.value());
}
if (isHttpGetOrHead) {
if (lastModifiedTimestamp > 0 && parseDateValue(response.getHeader(HttpHeaders.LAST_MODIFIED)) == -1) {
response.setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedTimestamp);
}
if (StringUtils.hasLength(etag) && response.getHeader(HttpHeaders.ETAG) == null) {
response.setHeader(HttpHeaders.ETAG, padEtagIfNecessary(etag));
}
}
} // 不知道干什么的以后再说
// 5
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
} //匹配拦截器 解释了为什么preHandle 要返回return
//如果prehandle ->return false 直接进入
//乳沟返回true 则进行一下个判断
this.interceptorIndex = i;
}
return true;
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
//6
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
// 7
private boolean synchronizeOnSession = false;
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav; // MV对象
checkRequest(request);// check 一下request
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) { //false
HttpSession session = request.getSession(false); //获得seesion
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; //mav{view:WEB-INF/web-resource/hello.html,...}
}
// 8
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) { //true
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
// 10
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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName(); //{WEB-INF/web-resource/hello.html}
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {//view:{url:viewname,....}
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() + "'");
}
}
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] "); //日志trace
}
try {
if (mv.getStatus() != null) { //
request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
```java
{
if (mv.getStatus() != null) { //
request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}