前言
今天主要给大家分享的是关于Spring MVC的知识内容,刚好是最近用到的知识点,所以今天就来给大家安利安利了!
那么,老规矩,话不多说!上干货.....
DispatcherServlet的设计
DispatcherServlet
的父类是FrameworkServlet
,FrameworkServlet
的父类则是HttpServletBean
。HttpServletBean
继承了Web容器所提供的HttpServlet
,所以它可以载入Web容器中的Servlet
。
DispatcherServlet
的工作大致可以分为两个部分:一个是初始化部分,由initServletBean
()启动,通过initWebApplicationContext
()方法最终调用DispatcherServlet
的initStrategies
方法。在这个方法里,DispatcherServlet
对MVC模块的其他部分进行了初始化,比如handlerMapping
,ViewResolver
等。另一个是对HTTP请求进行相应,作为一个servlet
,web容器会调用doGet()
,doPost()
方法,在经过FrameworkServlet
的processRequest
简单处理后,会调用DispatcherServlet
的doService()
方法,在这个方法中封装了doDispatch()
,这个doDispatch()
是Dispatcher实现MVC模式的主要部分。
下边我们来看源码:
DispatcherServlet的初始化
public final void init() throws ServletException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
}
//根据参数初始化bean的属性
try {
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
this.initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
} catch (BeansException var4) {
this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
throw var4;
}
//调用子类的initServletBean进行具体的初始化
this.initServletBean();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
}
}
FrameworkServlet的initServletBean方法
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring FrameworkServlet '" + this.getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
//初始化Spring Ioc容器
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
} catch (ServletException var5) {
this.logger.error("Context initialization failed", var5);
throw var5;
} catch (RuntimeException var6) {
this.logger.error("Context initialization failed", var6);
throw var6;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
}
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
//判断是否已经被初始化
if (this.webApplicationContext != null) {
//如果Web Ioc容器在启动的时候创建,那么就沿用它
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
if (!cwac.isActive()) {
//如果父容器为空的情况
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
//如果Spring Ioc容器还没有刷新,那么就进行刷新父容器上下文设置id等操作
this.configureAndRefreshWebApplicationContext(cwac);
}
}
}
//没有初始化,则查找是否有存在的Spring Web Ioc容器
if (wac == null) {
wac = this.findWebApplicationContext();
}
//没有初始化,也没有找到,则自己创建一个
if (wac == null) {
wac = this.createWebApplicationContext(rootContext);
}
//当onRefresh还没调用过,执行onRefresh方法
if (!this.refreshEventReceived) {
this.onRefresh(wac);
}
if (this.publishContext) {
//作为Servlet上下文属性发布到IOC容器
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
//创建
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class<?> contextClass = this.getContextClass();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + this.getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]");
}
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
} else {
//初始化MVC
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(this.getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(this.getContextConfigLocation());
this.configureAndRefreshWebApplicationContext(wac);
return wac;
}
}
上边代码展示了对Spring Ioc容器的初始化,除了SpringMVC上下文创建外,还需要启动SpringMVC的其他一些配置初始化,通过onRefresh
调用来完成。这个方法就在DispatcherServlet
当中,实际调用的initStrategies
进行配置
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
//初始化文件的解析
this.initMultipartResolver(context);
//本地初始化
this.initLocaleResolver(context);
//主题解析
this.initThemeResolver(context);
//处理器映射
this.initHandlerMappings(context);
//处理器适配器
this.initHandlerAdapters(context);
//handler的异常处理解析器
this.initHandlerExceptionResolvers(context);
//当处理器没有返回逻辑视图名等相关信息,自动将请求URL映射为路基视图名
this.initRequestToViewNameTranslator(context);
//视图解析器
this.initViewResolvers(context);
//flash
this.initFlashMapManager(context);
}
Spring MVC的核心组件
-
MultipartResolver
:文件解析器,用于支持服务器的文件上传 -
LocaleResolver
:国际化解析器,可以提供国际化的功能 -
ThemeResolver
:主题解析器,类似于软件皮肤的转换功能 -
HandlerMappings
:处理器映射器,它会包装用户提供一个控制器的方法和它的一些拦截器 -
HandlerAdapters
:处理器适配器,因为处理器会在不同的上下文运行,所以Spring MVC会找到合适的适配器,然后运行处理器服务方法 -
HandlerExceptionResolvers
:处理器异常解析器,处理器有可能产生异常,如果产生异常,则通过异常解析器来处理它 -
RequestToViewNameTranslator
:视图逻辑名称转换器,在控制器中返回一个视图的名称,通过它可以找到实际的视图。当处理器没有返回逻辑视图名等相关信息时,自动请求URL映射为逻辑视图名 -
ViewResolvers
:视图解析器,当控制器返回后,通过视图解析器会把逻辑视图名称进行解析,然后定位实际视图
Spring MVC流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器
- 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
- DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
- 执行处理器(Controller,也叫后端控制器)
- Controller执行完成返回ModelAndView
- HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
- DispatcherServlet响应用户
DispatcherServlet有接收请求,响应结果,转发等作用。有了DispatcherServlet之后,可以减少组件之间的耦合度
网友评论