03.SpringMVC之器
整体结构介绍
在Servlet的继承结构中一共有5个类,GenericServlet和HttpServlet在java中剩下的三个类HttpServletBean、FrameworkServlet和DispatcherServlet是SpringMVC中的这三个类直接实现三个接口:EnvironmentCapable、EnvironmentAware和ApplicationContextAware。
XXXAware在spring里表示对XXX可以感知,通俗点解释就是:如果在某个类里面想要使用spring的一些东西,就可以通过实现XXXAware接口告诉spring,spring看到后就会给你送过来,而接收的方式是通过实现接口唯一的方法setXXX,比如,有一个类想要使用当前的ApplicationContext,那么我们只需要让它实现ApplicationContextAware接口,然后实现接口中唯一的方法,void setApplicationContext(ApplicationContext applicationContext(会自动传过来,直接用))就可以了,spring会自动调用这个方法将applicationContext传给我们,我们只需要接收就可以了。
EnvironmentCapable,顾名思义,当然就是具有Environment的能力,也就是可以提供Environment,所以EnvironmentCapable唯一的方法是Environment getEnvironment(),用于实现EnvironmentCapable接口的类,就是告诉spring它可以提供Environment,当spring需要Environment的时候就会调用其getEnvironment方法跟它要
HttpServletBean
在HttpServletBean的init方法中,首先将Servlet中配置的参数使用BeanWrapper设置到DispatcherServlet的相关属性,然后调用模板方法initServletBean,子类就通过这个方法初始化
public final void init() throws ServletException {
// 1. 操作配置文件里的属性
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(),this.requiredProperties); if (!pvs.isEmpty()) {
try {
// 2.获取目标对象的beanwrapper对象
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
// 空实现
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}catch (BeansException ex) {
throw ex;
}
}
// 空方法 让子类实现
initServletBean();
}
BeanWrapper是Spring 提供的一个用来操作JavaBean属性的工具,使用它可以直接修改一个对象的属性
public class User{
String userName;
//省略get和set方法
}
public class BeanWrapperTest{
psvm{
User user = new User();
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(user);
bw.setPropertyValue("userName","张三");
sout(user.getUserName());
PropertyValue value = new PropertyValue("userName","李四");
sout(user.getUserName());
}
}
FrameworkServlet
FrameworkServlet继承HttpServletBean,FrameworkServlet的初始化入口方法是initServletBean
// org.springframework.web.servlet.FrameworkServlet
protected final void initServletBean() throws ServletException{
//初始化WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
//模板方法,子类可以覆盖在里面做一些初始化的工作
initFrameworkServlet();
} protected WebApplicationContext initWebApplicationContext(){
//获取rootContext
WebApplicationContext rootContext = WebApplicationContextUtils.getApplictionContext(getServletContext());
WebApplicationContext wac = null;
//如果已经通过构造方法设置了webApplicationContext
if(this.webApplicationContext != null){
wac = this.webApplicationContext;
if(wac instanceof ConfigurableWebApplicationContext){
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext ) wac;
if(!cwac.isActive()){
if(cwac.getParent() == null){
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac)
}
}
}
if(wac == null){
//当webApplicationContext已经存在ServletContext中时,通过配置在Servlet中的contextAttribute参数获取
wac = findWebApplicationContext();
}
if(wac == null)[
//如果webApplicationContext还没有创建,则创建一个
wac = createWebApplicationContext(rootContext);
}
if(!this.refreshEventReceived){
//当ContextRefreshedEvent事件没有触发时调用此方法,模板方法,可以在子类重写
onRefresh(wac);
}
if(this.publicContext){
//将ApplicationContext保存到ServletContext中
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName,wac);
}
return wac;
}
这个initWebApplicationContext方法做了三件事
1.获取spring的根容器rootContext
获取根容器的原理是,默认情况下spring会将自己的容器设置成ServletContext属性,默认根容器的key为org.springframework.web.context.WebApplicationContext.ROOT,所以获取根容器只需要调用ServletContext的getAttribute就可以了
2.设置webApplicationContext并根据情况调用onRefresh方法
3.将webApplicationContext设置到ServletContext中
这里在讲讲上面代码中的 wac == null 的几种情况:
1)、当 WebApplicationContext 已经存在 ServletContext 中时,通过配置在 servlet 中的 ContextAttribute 参数获取,调用的是 findWebApplicationContext() 方法
protected WebApplicationContext findWebApplicationContext() {
String attrName = getContextAttribute();
if (attrName == null) {
return null;
}
WebApplicationContext wac =
WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
}
return wac;
}
2)、如果 WebApplicationContext 还没有创建,调用的是 createWebApplicationContext 方法
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
//获取创建类型
Class<?> contextClass = getContextClass();
//删除了打印日志代码 //检查创建类型
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
//具体创建
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment());
wac.setParent(parent);
//并设置的 contextConfigLocation 参数传给 wac,默认是 WEB-INFO/[ServletName]-Servlet.xml
wac.setConfigLocation(getContextConfigLocation()); //调用的是下面的方法
configureAndRefreshWebApplicationContext(wac); return wac;
} protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
} wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
} postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
}
DispatcherServlet
OnRefresh方法是DispathcerServlet的入口方法,OnRefresh中简单地调用了initStrategis,在initStrategies中调用了9个初始化方法
//org.springframework.web.servlet.DispatcherServlet
protected void onRefresh (ApplicationContext context){
initStrategies(context);
} protected void initStrategies(Application context){
initMultipartResolver(context);
initLocalResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
03.SpringMVC之器的更多相关文章
- springmvc拦截器入门及其执行顺序源码分析
springmvc拦截器是偶尔会用到的一个功能,本案例来演示一个较简单的springmvc拦截器的使用,并通过源码来分析拦截器的执行顺序的控制.具体操作步骤为:1.maven项目引入spring依赖2 ...
- SpringMVC拦截器的使用
SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那 ...
- SpringMVC拦截器详解[附带源码分析]
目录 前言 重要接口及类介绍 源码分析 拦截器的配置 编写自定义的拦截器 总结 总结 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:h ...
- SpringMVC拦截器2(资源和权限管理)(作为补充说明)
SpringMVC拦截器(资源和权限管理) 1.DispatcherServlet SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServle ...
- SpringMVC拦截器(实现登录验证拦截器)
本例实现登陆时的验证拦截,采用SpringMVC拦截器来实现 当用户点击到网站主页时要进行拦截,用户登录了才能进入网站主页,否则进入登陆页面 核心代码 首先是index.jsp,显示链接 <%@ ...
- Spring+SpringMVC+MyBatis深入学习及搭建(十七)——SpringMVC拦截器
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7098753.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十六)--S ...
- SpringMVC拦截器Interceptor
SpringMVC拦截器(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似与servlet中的Filter. SpringMVC 中的Interceptor 拦截请求是通过Ha ...
- 五 : springMVC拦截器
springMVC拦截器的实现一般有两种方式 第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口 第二种方式是继承实现了HandlerInte ...
- 基于SpringMVC拦截器和注解实现controller中访问权限控制
SpringMVC的拦截器HandlerInterceptorAdapter对应提供了三个preHandle,postHandle,afterCompletion方法. preHandle在业务处理器 ...
随机推荐
- Java开源协同办公项目:数据中心,自定义查询语句使用教程
O2OA提供的数据管理中心,可以让用户通过配置的形式完成对数据的汇总,统计和数据分组展现,查询和搜索数据形成列表数据展现.也支持用户配置独立的数据表来适应特殊的业务的数据存储需求.本文主要介绍如何在O ...
- selenium异步爬取(selenium+Chromedriver)
在我们进行数据爬去的过程中,我们有时候会遇到异步加载信息的情况,以豆瓣电影分来排行榜为例,当我们在查看数据的过程中,会发现网页源码中并不包含我们想要的全部数据,但是当我们在进行向下滚动的时候,数据会一 ...
- ArrayList 深入浅出
ArrayList 特点:按添加顺序排列.可重复.非线程安全: 底层实现:数组 扩容原理:初始化集合时,默认容量为 0,第一次添加元素时扩容为 10,容量不够时扩容为原来容量的 1.5 倍. 这里扩容 ...
- 单机版kafka的安装
简单记录单机版kafka的安装:JDK1.8(jdk-8u131-linux-x64.rpm)zookeeper (zookeeper-3.4.10.tar.gz)kafka (kafka_2.12- ...
- Linux CentOS 7 安装配置vsftp
学习Linux时间不长,首次安装了vsftp,按照网上的各种帖子尝试配置,不过都没打到预期,不是被拒绝连接,就是连接超时,总之就是各种问题啊.当然了,不是别人配置的不对,而是自己不是太懂Linux,选 ...
- 开发工具IDE从入门到爱不释手(六)常用插件Git
Git 环境准备 本地基本操作 本地文件关联git管理 文件提交git Ctrl+K:提交 关联远程仓库 先注册github账号 连接本地 git菜单 撤销提交 追加提交 Code Review
- Python自动化测试面试题-用例设计篇
目录 Python自动化测试面试题-经验篇 Python自动化测试面试题-用例设计篇 Python自动化测试面试题-Linux篇 Python自动化测试面试题-MySQL篇 Python自动化测试面试 ...
- 第七篇--如何改变vs2017版的背景
改变背景 C:\Users\zsunny\AppData\Local\Microsoft\VisualStudio\15.0_9709afbe\Extensions\o0g0c52k.3od\Imag ...
- noip模拟29[简单的板子题](虽然我不会)
\(noip模拟29\;solutions\) 这次考试给我最大的伤害,让我意识到了差距 这场考试可以说是非常的简单,就是简单到,看两眼,打个表就有结果了 但是呢?我考得非常的完蛋,只有30pts 据 ...
- 图文实例解析,InnoDB 存储引擎中行锁的三种算法
前文提到,对于 InnoDB 来说,随时都可以加锁(关于加锁的 SQL 语句这里就不说了,忘记的小伙伴可以翻一下上篇文章),但是并非随时都可以解锁.具体来说,InnoDB 采用的是两阶段锁定协议(tw ...