整体结构介绍

在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. 【开发工具】-- IDEA集成Git在实际项目中的运用

    1.企业实际项目中Git的使用 在实际的企业项目开发中,我们一般Java的项目在公司都有自己的局域网代码仓库,仓库上存放着很多的项目.以我工作过的公司如华为的项目,一般是存放在企业内部的CodeHub ...

  2. 【NOIP2007】Hanoi双塔问题

    题目描述 给定A.B.C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形). 现要将这些圆盘移到C柱上 ...

  3. 注解@ConfigurationProperties使用方法(二十)

    前言 最近在思考使用java config的方式进行配置,java config是指基于java配置的spring.传统的Spring一般都是基本xml配置的,后来spring3.0新增了许多java ...

  4. SQlL 中 where 1=1

    提升某种执行效率? 其实,1=1 是永恒成立的,意思无条件的,也就是说在SQL语句中有没有这个1=1都可以. 这个1=1常用于应用程序根据用户选择项的不同拼凑where条件时用的. 如:web界面查询 ...

  5. jenkins资源下载地址(软件、插件等)

    jenkins资源下载地址(软件.插件等) 1. 镜像1:清华镜像 2 .镜像2:http://mirrors.jenkins-ci.org/ 3. 官方下载地址:https://jenkins.io ...

  6. K8S系列第三篇(Docker网络)

    目录 docker 网络 Docker 的四种网络模 一.网络基础 1.网络名称空间介绍 2.创建一个命名空间 1)Veth设备对 2)Veth设备操作 1> 创建Veth设备对 2> 绑 ...

  7. [考试总结]noip模拟14

    咕掉了好长时间,现在终于回来了.. 这次考试炸裂得很完蛋,直接分数上天. \(T1\) 本来想打一个记忆化搜索,然而老是通过不了样例,然后就挂了,只剩下了垃圾的 \(30pts\) 部分分数. 然而到 ...

  8. ifix历史数据(H04/H08/H24)转换为CSV文件导出

    在最近的一次环保数据维护中,由于自己疏忽导致数据库中TP值并未有效记录,还好历史趋势有相关记录,问题是我该如何将.H24文件记录导出?在逛论坛后,无意发现一款工具解决了我的燃眉之急-HTD2CSV.e ...

  9. linux中的dhcp

    目录 一.DHCP服务 二.DHCP的租约过程 三.使用DHCP动态配置主机地址 四.安装DHCP服务器 一.DHCP服务 ① DHCP (Dynamic HostConfiguration Prot ...

  10. C++ //拷贝构造函数调用时机//1.使用一个已经创建完毕的对象来初始化一个新对象 //2.值传递的方式给函数参数传值 //3.值方式返回局部对象

    1 //拷贝构造函数调用时机 2 3 4 #include <iostream> 5 using namespace std; 6 7 //1.使用一个已经创建完毕的对象来初始化一个新对象 ...