整体结构介绍

在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之器的更多相关文章

  1. springmvc拦截器入门及其执行顺序源码分析

    springmvc拦截器是偶尔会用到的一个功能,本案例来演示一个较简单的springmvc拦截器的使用,并通过源码来分析拦截器的执行顺序的控制.具体操作步骤为:1.maven项目引入spring依赖2 ...

  2. SpringMVC拦截器的使用

    SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那 ...

  3. SpringMVC拦截器详解[附带源码分析]

    目录 前言 重要接口及类介绍 源码分析 拦截器的配置 编写自定义的拦截器 总结 总结 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:h ...

  4. SpringMVC拦截器2(资源和权限管理)(作为补充说明)

    SpringMVC拦截器(资源和权限管理) 1.DispatcherServlet SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServle ...

  5. SpringMVC拦截器(实现登录验证拦截器)

    本例实现登陆时的验证拦截,采用SpringMVC拦截器来实现 当用户点击到网站主页时要进行拦截,用户登录了才能进入网站主页,否则进入登陆页面 核心代码 首先是index.jsp,显示链接 <%@ ...

  6. Spring+SpringMVC+MyBatis深入学习及搭建(十七)——SpringMVC拦截器

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7098753.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十六)--S ...

  7. SpringMVC拦截器Interceptor

    SpringMVC拦截器(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似与servlet中的Filter. SpringMVC 中的Interceptor 拦截请求是通过Ha ...

  8. 五 : springMVC拦截器

    springMVC拦截器的实现一般有两种方式 第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口 第二种方式是继承实现了HandlerInte ...

  9. 基于SpringMVC拦截器和注解实现controller中访问权限控制

    SpringMVC的拦截器HandlerInterceptorAdapter对应提供了三个preHandle,postHandle,afterCompletion方法. preHandle在业务处理器 ...

随机推荐

  1. XP共享打印机

    1.开启GUEST:右击"我的电脑"管理--用户--GUEST开启 2.运行--GPEDIT.MSC--计算机管理-WINDOWS设置--安全设置--本地策略--用户权利指派--允 ...

  2. [刘阳Java]_SpringMVC文件上传第1季_第10讲

    今天来介绍一个关于SpringMVC框架的文件上传功能.首先我个人感觉SpringMVC框架的文件上传还是要比Struts2框架要好用一些,灵活性更强.因为SpringMVC框架的文件上传有几种不同的 ...

  3. Kettle——简介

    Kettle是一款国外开源的ETL工具,纯java编写,可以在Window.Linux.Unix上运行,数据抽取高效稳定 Kettle 的主作者是 Matt ,他在 2003 年就开始了这个项目,在  ...

  4. ubuntu16.04细节设置

    1.查看无线网卡名称 $ iwconfig ------------------ lo no wireless extensions. eth1 no wireless extensions. eth ...

  5. 使用Elastic Job的分片配置加速任务执行和提高资源利用率

    上一篇,我们介绍了如何使用Elastic Job实现定时任务.解决了使用@Scheduled来实现时候存在的竞争问题,同时也实现了定时任务的高可用执行. 然而,还有一类问题是我们在做定时任务时候容易出 ...

  6. 2021 NOI冬令营

    2021 NOI冬令营 -- 本来想写得稍微文艺一点的,但是停课这么久已经退化到不会写文章了. 毕竟省选了我才来补的,时间也过去很久了. 毕竟这次我没有获得任何奖项. 我唯一的获得就是-- --好好看 ...

  7. ODOO14 ---系统启动方式

    一.通过pycharm启动 1.配置启动面板: 点击启动即可: 第二种.通过CMD窗口启动:进入到odoo-bin的目录下,执行:python E:\odoo14\odoo14\odoo-bin  这 ...

  8. C++第三十五篇 -- 写第一个驱动开发程序

    VS2017+WDK+VMware12+Win10环境配置完毕,接下来写第一个驱动程序. 1.新建一个KMDF的程序. 2.配置项目属性. 3.编译项目.一般这里应该成功,我一台电脑成功了,另一台电脑 ...

  9. LUSE: 无监督数据预训练短文本编码模型

    LUSE: 无监督数据预训练短文本编码模型 1 前言 本博文本应写之前立的Flag:基于加密技术编译一个自己的Python解释器,经过半个多月尝试已经成功,但考虑到安全性问题就不公开了,有兴趣的朋友私 ...

  10. 大数据学习(19)—— Flume环境搭建

    系统要求 Java1.8或以上 内存要足够大 硬盘足够大 Agent对源和目的要有读写权限 Flume部署 我这8G内存的电脑之前搭建Hadoop.Hive和HBase已经苟延残喘了,怀疑会卡死,硬着 ...