Spring MVC 学习 -- 创建过程

Spring MVC我们使用的时候会在web.xml中配置

   <servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-web.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

1.核心的类结构

  继承结构主要有五个类,GenericServlet和HttpServlet 是Java的,HttpServletBean、FrameworkServlet和DispatcherServlet是Spring MVC的。

    在图中还有三个接口:EnvironmentCapable、EnvironmentAware和ApplicationContextAware~

    XXXAware 在spring里标识对XXX可以感知 -- 白话的意思就是:某个类如果想要使用spring的一些东西,就可以通过实现XXXAware接口告诉spring,spring看到后会给你送过来,而接收的方式是通过实现接口唯一的setXXX

 public interface ApplicationContextAware extends Aware {

 void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

 }

源码如上,使用的话写一个类实现ApplicationContextAware,然后实现setApplicationContext()方法就行,spring为自动调用这个方法将applicationContext传给我们。 

而EnvironmentCapable是为了实现getEnvironment去拿到ServletContext、ServletConfig、JndiProperty、系统环境变量和系统属性。

2.HttpServletBean

     public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
} // Set bean properties from init parameters.
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
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) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
} // Let subclasses do whatever initialization they like.
initServletBean(); if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}

主要看init()方法, 使用了BeanWrapper这个类对象,BeanWrapper是操作JavaBean的工具类,主要就是对属性进行操作。

3.FrameworkServlet

这个类是通过HttpServletBean中的initServletBean()方法进入的。

     protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis(); try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
} if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}

核心代码就try里面包含的两句,很显然主要用来初始化WebApplicationContext和初始化FrameworkServlet的。

     protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null; if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
} if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);
} if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
} return wac;
}

主要做了三件事:

  • 获取spring的根容器rootContext
  • 设置webApplicationContext并根据情况调用onRefresh方法
  • 将webApplicationContext设置到ServletContext中

4.DispatcherServlet

通过上面onRefresh()方法,调用initStrategies()方法,初始化策略组件。具体的内容就是用来初始化9个组件,每个组件的代码不一一贴出来了, 这几个方法都会去调用getDefaultStrategies()方法。

 protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(classNames.length);
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
}
}
return strategies;
}
else {
return new LinkedList<T>();
}
}

5.代码测试

配置内容都不再贴了,启动Tomcat,然后去请求某个controller地址,进入HttpServletBean的init()方法

然后继续,因为WebApplicationContext是null,会进入

然后configureAndRefreshWebApplicationContext方法中会执行refresh(),这部分可以看spring bean加载过程和实例化。

Spring MVC 学习 -- 创建过程的更多相关文章

  1. Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目

    Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目 Spring Tool Suite 是一个带有全套的Spring相关支持功能的Eclipse插件包. ...

  2. Spring MVC 学习笔记12 —— SpringMVC+Hibernate开发(1)依赖包搭建

    Spring MVC 学习笔记12 -- SpringMVC+Hibernate开发(1)依赖包搭建 用Hibernate帮助建立SpringMVC与数据库之间的联系,通过配置DAO层,Service ...

  3. Spring MVC 学习笔记一 HelloWorld

    Spring MVC 学习笔记一 HelloWorld Spring MVC 的使用可以按照以下步骤进行(使用Eclipse): 加入JAR包 在web.xml中配置DispatcherServlet ...

  4. spring MVC处理请求过程及配置详解

    本文主要梳理下Spring MVC处理http请求的过程,以及配置servlet及业务application需要的常用标签,及其包含的意义. spring MVC处理请求过程 首先看一个整体图 简单说 ...

  5. Spring MVC 学习总结(九)——Spring MVC实现RESTful与JSON(Spring MVC为前端提供服务)

    很多时候前端都需要调用后台服务实现交互功能,常见的数据交换格式多是JSON或XML,这里主要讲解Spring MVC为前端提供JSON格式的数据并实现与前台交互.RESTful则是一种软件架构风格.设 ...

  6. Spring MVC 学习总结(一)——MVC概要与环境配置 转载自【张果】博客

    Spring MVC 学习总结(一)--MVC概要与环境配置   目录 一.MVC概要 二.Spring MVC介绍 三.第一个Spring MVC 项目:Hello World 3.1.通过Mave ...

  7. spring MVC处理请求过程

    spring MVC处理请求过程 首先看一个整体图 简单说下各步骤: handlerMapping handlerMapping将请求映射到处理器,即图中的HandlerExecutionChain. ...

  8. Spring MVC 学习总结(十)——Spring+Spring MVC+MyBatis框架集成(IntelliJ IDEA SSM集成)

    与SSH(Struts/Spring/Hibernate/)一样,Spring+SpringMVC+MyBatis也有一个简称SSM,Spring实现业务对象管理,Spring MVC负责请求的转发和 ...

  9. Spring MVC 学习笔记8 —— 实现简单的用户管理(4)用户登录

    Spring MVC 学习笔记8 -- 实现简单的用户管理(4)用户登录 增删改查,login 1. login.jsp,写在外面,及跟WEB-INF同一级目录,如:ls Webcontent; &g ...

随机推荐

  1. Html中设置访问页面不在后进行其他页面跳转

    Html中设置访问页面不在后进行其他页面跳转 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" & ...

  2. [Unity3D]UI界面之瞄准镜设置说明

    9空格设计 : 比如说4个角的图案固定,拉伸的时候不受影响 通过设置 左上右下来: 通过创建Image对象,将设置好的图片关联到Source Image 调整瞄准镜跟随飞机, 注意这里设置的Z轴向量是 ...

  3. c# c++ oc java || mac android ios

    Unity 使用C/C++ 跨平台终极解决方案(PC,iOS,Android,以及支持C/C++的平台) http://blog.csdn.net/fg5823820/article/details/ ...

  4. synthesize的作用

    @synthesize是对属性的实现,实际上就是制定setter和getter操作的实例变量的名称   举个栗子: @synthesize array;  默认操作的实例变量和属性同名 @synthe ...

  5. C#

    1.类型推导 ; Console.WriteLine(age.GetType().ToString()); var 关键字还可以配合生成匿名类型,如: , Time = }: 如果有可以将对象转成JS ...

  6. SqlServer 常用函数

    case ..   when ..   then ..   else   ..  end

  7. linux -目录结构

    摘自:http://www.comptechdoc.org/os/linux/usersguide/linux_ugfilestruct.html 这个目录结构介绍是我目前看到介绍最全的,有时间在翻译 ...

  8. 如何在ARM中创建Express Route

    很早之前就想试试Azure的express route,但是一直没有找到合适的机会,正好有个客户需要上express route,所以最近先自己研究研究,防止在做poc的时候耗费更多时间,本次场景我们 ...

  9. runtime第二部分成员变量和属性

    接上一篇 http://www.cnblogs.com/ddavidXu/p/5912306.html 转载来源http://www.jianshu.com/p/6b905584f536 http:/ ...

  10. PHP之compact()函数

    PHP之compact()函数 compact()函数将变量转化为数组: <?php //直接调用函数 $a=1;$b=3;$c=4; var_dump($a,$b,$c); //自定义函数实现 ...