本文主要介绍一下SpringMVC中射击的一些基本概念,后面还会继续补充…
一、servlet简介
1.1.什么是servlet
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
我们可以使用servlet创建一个服务端应用,来处理http客户端请求,用来操作/获取数据库数据.
1.2.servlet应用架构
1.3.Java Servlet
1.3.1.java对servlet的实现
java库中对servlet定义如下,你可以实现以下接口,在service方法里实现自己的业务逻辑,打包后就可以在web服务器上运行了.
早期的servlet应用一般都是通过这种方式实现.
package javax.servlet;
import java.io.IOException;
public interface Servlet {
//初始化servlet配置
public void init(ServletConfig config) throws ServletException;
//获取servlet配置
public ServletConfig getServletConfig();
//处理请求
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
//获取servlet应用信息
public String getServletInfo();
//销毁servlet
public void destroy();
}
1.3.2.GenericServlet 和HttpServlet
1.3.2.1.GenericServlet
对Servlet接口关于ServletConfig相关操作的实现.
- 持有ServletConfig类
- 实现了init(ServletConfig config) 方法,但是定义了init()空方法,可以有子类覆盖.不建议直接覆盖init(ServletConfig config) .
- 该类是一个抽象类,将Servlet的service方法改成了抽象方法
1.3.2.2.HttpServlet
HttpServlet主要作用是按照当前http请求的method类型,调用不同的方法,主要有以下几种:
- doGet
- doHead
- doPost
- doPut
- doDelete
- doOptions
- doTrace
该类可以作为servlet应用开发中一个servlet继承的父类,我们只需要继承相应的doXXX方法来实现我们的逻辑.
二、MVC模式
为什么我们现在很少直接通过实现servlet或继承HttpServlet,来开发我们的程序?
在实际的开发中,我们最常用请求方式一般为GET、POST,而这两者,在大部分情况都会传入参数,并返回复杂数据结果.
那么如果直接通过实现servlet或继承HttpServlet来构建我们的应用,那么我们将会话费很多逻辑在参数的获取、参数校验、返回数据格式化上.
所以就出现了MVC模式.
2.1.MVC模式
MVC代表Model-View-Controller 即:模型-视图-控制器,这种模式可以进行很好的应用程序的分层开发.
- Model:模型,模型代表一个存取数据的对象或Java POJO
- View:视图,代表模型包含的数据的可视化
- Controller:控制器,控制器作用与模型和视图上,用于处理用户请求,并将数据流向模型对象,并在数据变化时更新视图,使得视图和模型解耦.
MVC架构图如下:
有兴趣的可以了解一下:struts 和struts2 、jsp,本文主要讲springMVC ,这些内容不在这里做介绍了.
三、springMVC原理
3.1.SpringMVC简介
官网地址:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-config
SpringMVC 是基于Servlet API构建的原始Web框架,正式名称是Spring Web MVC.
3.2.Spring MVC主要类结构
3.2.1.整体UML类图
3.2.2.ModelAndView
ModelAndView 持有springMVC框架中的model和View两个元素,代表了一个handler处理的结果,这个结果将会被DispatcherServlet解析.
定义如下:
public class ModelAndView {
/** View instance or view name String
当前视图的名称 或视图实例
*/
@Nullable
private Object view;
/** Model Map
当前模型数据集合
*/
@Nullable
private ModelMap model;
/** Optional HTTP status for the response
http请求状态
*/
@Nullable
private HttpStatus status;
/** Indicates whether or not this instance has been cleared with a call to {@link #clear()} */
private boolean cleared = false;
public ModelAndView() {
}
public ModelAndView(String viewName) {
this.view = viewName;
}
public ModelAndView(View view) {
this.view = view;
}
public ModelAndView(String viewName, @Nullable Map<String, ?> model) {
this.view = viewName;
if (model != null) {
getModelMap().addAllAttributes(model);
}
}
public ModelAndView(View view, @Nullable Map<String, ?> model) {
this.view = view;
if (model != null) {
getModelMap().addAllAttributes(model);
}
}
public ModelAndView(String viewName, HttpStatus status) {
this.view = viewName;
this.status = status;
}
public ModelAndView(@Nullable String viewName, @Nullable Map<String, ?> model, @Nullable HttpStatus status) {
this.view = viewName;
if (model != null) {
getModelMap().addAllAttributes(model);
}
this.status = status;
}
public ModelAndView(String viewName, String modelName, Object modelObject) {
this.view = viewName;
addObject(modelName, modelObject);
}
public ModelAndView(View view, String modelName, Object modelObject) {
this.view = view;
addObject(modelName, modelObject);
}
}
ModelView 会根据返回的view名称找到对应的视图类或文件,进行渲染,渲染的数据存放在ModelMap中,ModelMap是一个LinkedHashMap,key为模型的名称,value为模型数据.
3.2.3.Controller
3.2.3.1.源码
@FunctionalInterface
public interface Controller {
/**
处理request、repsonse并返回一个ModelAndView ,由DispatcherServlet调用render方法渲染
**/
@Nullable
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
3.2.3.2.Controller子类体系
3.2.3.2.1.AbstractController
AbstractController的主要作用有两个
- 继承了WebContentGenerator,该类支持http 缓存,使得AbstractController具有的缓存功能.
- synchronizeOnSession: session同步控制
缓存功能实现
通过设置header中的Cache-Control来实现.
protected final void applyCacheControl(HttpServletResponse response, CacheControl cacheControl) {
String ccValue = cacheControl.getHeaderValue();
if (ccValue != null) {
// Set computed HTTP 1.1 Cache-Control header
response.setHeader(HEADER_CACHE_CONTROL, ccValue);
if (response.containsHeader(HEADER_PRAGMA)) {
// Reset HTTP 1.0 Pragma header if present
response.setHeader(HEADER_PRAGMA, "");
}
if (response.containsHeader(HEADER_EXPIRES)) {
// Reset HTTP 1.0 Expires header if present
response.setHeader(HEADER_EXPIRES, "");
}
}
}
synchronizeOnSession说明:
sesion同步的含义:当前一个session会话中,之后的ajax请求,必须等待之前的ajax请求完成之后,才能执行.
@Override
@Nullable
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
response.setHeader("Allow", getAllowHeader());
return null;
}
// Delegate to WebContentGenerator for checking and preparing.
checkRequest(request);
prepareResponse(response);
// Execute handleRequestInternal in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return handleRequestInternal(request, response);
}
}
}
return handleRequestInternal(request, response);
}
handleRequest方式是处理request的核心方法,在执行handleRequestInternal处理数据之前,会先获取当前session的锁,这样就会导致当前session的其他请求,无法响应.
配置方式:
<init-param>
<param-name>synchronizeOnSession</param-name>
<param-value>true</param-value>
</init-param>
3.2.4.View
3.2.4.1.View子类体系
从上图我们可以看出,view主要分为两类:
- Json 渲染(但是springMVC 的json接口,不是通过该方式实现的,在spring 请求流程里面会讲到)
- 基于url渲染模版
- 重定向
- 模版渲染: freemark,pdf.xslt,script模版
这里不对这些类进行详细介绍了,后面会出详细介绍文章.
view类的作用就是根据不同的类型选择不同的实现来渲染数据.
3.2.5.ViewResovler
3.2.5.1.ViewResovler体系
3.2.5.2.ViewResovler的作用
细心的可以发现,ViewResovler和View的实现有对应关系.
ViewResovler是用来做什么的?
我们看下spring 源码关于ViewResolver的注释:
/***
* Interface to be implemented by objects that can resolve views by name.
一个可以用来根据名称来解析view对象的接口.
*
* <p>View state doesn't change during the running of the application,
* so implementations are free to cache views.
View对象的状态在程序运行时时不会改变的,所以实现类可以缓存这些view对象.
*
* <p>Implementations are encouraged to support internationalization,
提倡实现类支持国际化
***/
从注视可以看出ViewResovler是一种将逻辑视图转换为实际View的一种机制.
正常的handler会返回一个ModelView对象,这里面包含视图,但是在我们开发时,可以返回一个视图名称,框架可以根据这个名称去找到对应的视图,提高开发效率、和代码结构.
3.2.5.3.ViewResovler主要子类
-
ViewResolverComposite:代理类,持有所有的ViewResovler实现.
-
AbstractCachingViewResolver:该类主要缓存View对象
-
ContentNegotiatingViewResolver:根据请求文件名或header信息,解析返回的view
-
BeanNameViewResolver: 将view名称和bean 名称做关联,查找该view名称时,实际去查找对应的Bean对象
-
UrlBasedViewResolver:实际最重要的一个,通过url来查找对应视图名称,最常使用的:定义prefix/suffix,Example: prefix=“/WEB-INF/jsp/”, suffix=“.jsp”, viewname=“test” -> “/WEB-INF/jsp/test.jsp”,大部分常用的ViewResovler都是直接继承该类,也可以继承它来自定义自己的ViewResovler
3.2.6.HandlerMapping和HandlerAdapter
3.2.6.1.HandlerMapping和HandlerAdapter体系图
3.2.6.2.HandlerMapping
/** Interface to be implemented by objects that define a mapping between
* requests and handler objects.
**/
HandlerMapping的子类定义了request和handler子类之间的对应关系.
也就是说,当DispatcherServlet收到一个请求时,会根据HandlerMapping找到,一个处理该请求的handler,一般是一个handler处理链.
子类主要分为两大类:
- AbstractHandlerMethodMapping: 定义了url和方法级的对应关系.通过该方法,可以找到对应的HandlerMethod
- AbstractUrlHandlerMapping: url和类级别的关系.通过该类可以找到对应的Controller类
3.2.6.3.HandlerAdapter
/***
* <p>Interface that must be implemented for each handler type to handle a request.
* This interface is used to allow the {@link DispatcherServlet} to be indefinitely
* extensible. The {@code DispatcherServlet} accesses all installed handlers through
* this interface, meaning that it does not contain code specific to any handler type.
**/
HandlerAdapter的主要作用就是DispatcherServlet通过它去执行每个类型的handler 的逻辑.