Spring 详解(四):Spring MVC
1. 跟踪Spring请求
使用Spring构建的Web程序中,请求最先接触到的是Spring中的DispatcherServlet。从图中可以看见DispatcherServlet相当一个调度者,所有的核心环节最终都要汇总到DispatcherServlet中。
对图流程的概要说明:
- DispatcherServlet其实是一个Servlet,用于拦截客户端的所有请求。在这里一个单实例的Servlet将请求委托给应用程序的其他组件来执行实际的处理。
- DispatcherServlet的任务是将请求发送给Spring MVC控制器(controller)。DispatcherServlet会查询一个或多个处理器映射(handler mapping)来确定请求应该将请求发送给哪个控制器。处理器映射会根据请求所携带的URL信息来进行决策。
- 控制器会根据请求参数进行相关的业务处理,一般情况下控制器只负责解析请求中的参数,然后调用其它组件(如业务处理组件)并传递参数来处理请求。控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示。这些信息被称为模型(model)。不过仅仅给用户返回原始的信息是不够的——这些信息需要以用户友好的方式进行格式化,一般会是HTML。所以,信息需要发送给一个视图(view),通常会是JSP。
- 在处理完成客户的请求后会返回逻辑视图的名称和模型。
- DispatcherServlet会调用视图解析器,将逻辑视图名称解析成物理视图名称(也就是视图在项目中的路径)。这样,控制器就不会与特定的视图相耦合,传递给DispatcherServlet的视图名并不直接表示某个特定的JSP。实际上,它甚至并不能确定视图就是JSP。相反,它仅仅传递了一个 逻辑名称,这个名字将会用来查找产生结果的真正视图。DispatcherServlet将会使用视图解析器(view resolver) 来将逻辑视图名匹配为一个特定的视图实现,它可能是也可能 不是JSP。 既然DispatcherServlet已经知道由哪个视图渲染结果,那请求的任务基本上也就完成 了。
- DispatcherServlet会调用视图实现,渲染视图,将模型交付给视图。
- 通过响应对象response将渲染完成的视图传递给客户端。这样就完成了响应。
2. 搭建Spring MVC 环境
ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法,然后它会装载Spring AppliconContext.xml信息,装载ContextLoader ApplicationContext容器。
2.1 配置Dispatcher
我们通常会在web.xml文件中配置DispatcherServlet。但是,借助于Servlet 3.0规范和Spring3.1功能的增强,这种方式已经不是唯一方式。我们将使用java类来配置DispatcherServlet。MVCWebAppInitializer 继承 AbstractAnnotationConfigDispatcherServletInitializer,这个类已经隐身的帮我配置了DispatcherServlet。
public class MVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{RootConfig.class};}@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{WebAppConfig.class};}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}
}
在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果能发现的话,就会用它来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer。这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给他们来完成。Spring 3.2 引入了一个便利的AbstractAnnotationConfigDispatcherServletInitializer。因为我们的MVCWebAppInitializer继承自AbstractAnnotationConfigDispatcherServletInitializer所以当部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。
实际上AbstractAnnotationConfigDispatcherServletInitializer会同时创建Dispatcher和ContextLoaderListener。getServletConfigClasses()方法将会创建DispatcherServlet应用上下文的Bean容器。getRootConfigClasses()方法将会创建ContextLoaderListener应用上下文Bean容器。
2.2 两个应用上下文
DispatcherServlet应用上下文的Bean容器:用来加载包含Web组件的Bean,比如控制器、实体解析器以及处理器映射、过滤器、拦截器等。
ContextLoaderListener应用上下文Bean容器:要加载应用中的其他Bean,比如这些Bean通常是后端驱动应用程序的中间层和数据层组件。
下面我们来看具体的两个Spring容器的实现:
DispatcherServlet应用上下文的Bean容器
@Configuration
@EnableWebMvc
@ComponentScan("com.hust.edu.controller")
public class WebAppConfig extends WebMvcConfigurerAdapter{@Beanpublic ViewResolver viewResolver(){InternalResourceViewResolver viewResolver=new InternalResourceViewResolver();viewResolver.setPrefix("/");viewResolver.setSuffix(".jsp");viewResolver.setExposeContextBeansAsAttributes(true);return viewResolver;}@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}
}ContextLoaderListener应用上下文Bean容器
@Configuration
@ComponentScan(basePackages = "com.hust.edu",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)
})
public class RootConfig {}
3. 深入理解这两个应用上下文容器
- getRootConfigClasses: Specify @Configuration and/or @Component classes to be provided to the root application context.(将有@Component注解或者@Component注解的配置类提供给根应用上下文)
- getServletConfigClasses:Specify @Configuration and/or @Component classes to be provided to the dispatcher servlet application context.(将有@Component注解或者@Component注解的配置类提供给DispatcherServlet应用上下文)
我们一定会疑惑,这里在Web应用程序中有两个Spring IOC容器创建,那么Web应用程序到底会使用哪个容器呢?现在通过我们下面的解释,我们将解答这个问题。
在Spring中,应用上下文(ApplicationContext)的实例是可以范围化(Scoped)的,在Web MVC框架中,每个DispatcherServlet都可以有自己的Web应用上下文(WebApplicationContext),每个DispatcherServlet自己的WebApplicationContext继承所有的在根应用上下文中的bean。根应用上下文应该包含在其他DispatcherServlet中会用到的bean,比如DataSource等,这些在根应用上下文中的bean可以在DispatcherServlet自己的WebApplicationContext中被重载。
在Spring MVC中我们其实是可以创建出多个DispatcherServlet的(只要创建多个继承自AbstractAnnotationConfigDispatcherServletInitializer的类即可)。而每个DispatcherServlet有自己的应用上下文(WebApplicationContext),这个应用上下文只针对这个DispatcherServlet有用(比如本博客开头描述的图)。这也就是getServletConfigClasses的作用,获取这个DispatcherServlet的应用上下文的配置类。
而除了每个DispatcherServlet配置类的应用上下文之外,还有一个根应用上下文,这个应用上下文的作用是为了在多个DispatcherServlet之间共享Bean,比如数据源Bean,这就是getRootConfigClasses的作用,用于返回根应用上下文的配置类。
Spring框架的机制会保证如果在当前DispatcherServlet的应用上下文中没有找到想要的bean时,会去根应用上下文中去找。
Web应用中有DispatcherServlet时,每个DispatcherServlet的bean如Controller,ViewResolver,HandlerMapping等,均在getServletConfigClasses返回的类中配置。其中每个DispatcherServlet表示拦截器将拦截的不同URL,而这个生成的IOC容器将保存这些不同URL的Controller,ViewResolver,HandlerMapping。而一些公共的bean,如Services,Repository均在getRootConfigClasses返回的类中配置。
当Web应用中只有一个DispatcherServlet中时,可以将所有的bean配置均写在根应用上下文中。DispatcherServlet获取想要的bean时,如果没有在自己的应用上下文中找到,则会自动到根应用上下文中去找。这也就是Spring MVC的ApplicationContext继承机制。
Spring 详解(四):Spring MVC相关推荐
- JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试
Spring框架学习路线 Spring的IOC Spring的AOP,AspectJ Spring的事务管理,三大框架的整合 Spring框架概述 什么是Spring? Spring是分层的Java ...
- Spring 详解Bean的后置处理器
Bean的后置处理器详解: Spring当中的后置处理器是Spring体用的一个扩展点,开发者只要去实现,Spring当中的BeanPostProcessor接口,那么就能插手SpringBean实例 ...
- springboot 详解 (四)redis filter
---------------------------------------------------------------------------------------------------- ...
- linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)
linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...
- Android Studio 插件开发详解四:填坑
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78265540 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...
- 数据结构--图(Graph)详解(四)
数据结构–图(Graph)详解(四) 文章目录 数据结构--图(Graph)详解(四) 一.图中几个NB的算法 1.普里姆算法(Prim算法)求最小生成树 2.克鲁斯卡尔算法(Kruskal算法)求最 ...
- .NET DLL 保护措施详解(四)各操作系统运行情况
我准备了WEB应用程序及WinForm应用程序,分别在WIN SERVER 2012/2008/2003.Win7/10上实测,以下为实测结果截图: 2012 2008 2003 WIN7 WIN10 ...
- mybatis 鉴别其_MyBatis之Mapper XML 文件详解(四)-JDBC 类型和嵌套查询
MyBatis之Mapper XML 文件详解(四)-JDBC 类型和嵌套查询 白玉 IT哈哈 支持的 JDBC 类型 为了未来的参考,MyBatis 通过包含的 jdbcType 枚举型,支持下面的 ...
- App Widgets 详解四 RemoteViews、RemoteViewsService和RemoteViewsFactory
导读 本篇文章将介绍"集合视图",App Widget 复杂布局的实现 App Widget 小部件系列其他文章链接 App Widgets 详解一 简单使用 App Widget ...
- java实现标准化考试系统详解(四)-----初始化操作实现
(一)初始化操作实现 如上图所示当管理员需要更改适用工程.试题数量.考试时间时直接在文本中更改就好我们只需要每次在用户打开程序时初始化这些参数就可以 1.初始化试题模型,这里需要实现随机抽题,方法是用 ...
最新文章
- 如安装flashplayer旧版本
- 如何在AxureRP7中使用FontAwesome字体
- 30岁自学python找工作-30岁新手入门python!尝试人生另一种可能
- Google谷歌首席科学家:神经网络的奇妙特性与应用
- ios c语言编译环境搭建,iOS开发之runtime(一):runtime调试环境搭建
- [vue] 什么是双向绑定?原理是什么?
- Daily tips-7月
- python selenium 关闭窗口_Selenium快速上手实战 | 上篇
- Unity3D教程:尽量避免使用foreach
- 修改typora设置能够配对latex行间公式$ $
- UFS Host基础特性分析 -- 软件部分
- IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:t
- 功能测试VS性能测试
- 六、C++离散傅里叶逆变换
- 怎么在看视频时保持电脑屏幕不灭,干货到,WIN10如何设置电脑屏幕一直亮着
- RK3399PRO-RKNN_DEMO模块开发最新资料下载
- BMR(基础代谢率)计算器
- 图像处理 OpenCV简介
- python 中文乱码处理分析过程
- 仿微信头像图片裁剪并压缩到100K以下到本地
热门文章
- mysql客户端( Navicat)远程登录操作问题 1142-create command denied to user×××
- 终于写了自己第一个有些用处的代码,留念留念,是模糊搜索并复制到指定文件夹...
- 0112作业 字符串练习
- 中国国家气象局天气预报信息接口
- 预览文章: c++ primer学习笔记,二:标准库类型
- 删除不同粒度的事实表记录中重复的度量值数据的SQL语句
- leetcode 64. 最小路径和
- Leetcode 121 动态规划(原名字不通过审核)
- 世界上公认最难的十大学科
- 如何停oracle的job,ORACLE如何停止一个JOB