`
greemranqq
  • 浏览: 966630 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

spring mvc - 源码解析(一) 初始化

阅读更多

     了解spring 的原理,一般从 官方提供的运行机制的图,然后根据代码 进行源码分析,就可以了,这里先从spring mvc 启动开始分析。先来看看web.xml 的配置吧。这里基于spring 3.2

    

<!-- 启动监听 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/classes/META-INF/spring/applicationContext*.xml</param-value>
</context-param>

<!-- app 请求 -->
<servlet>
	<servlet-name>SpringMVCServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
			<init-param>
				<param-name>contextConfigLocation</param-name>
				<param-value>
				/WEB-INF/config/app-config.xml
			</param-value>
			</init-param>
			<load-on-startup>1</load-on-startup>
		</servlet>
		<servlet-mapping>
			<servlet-name>SpringMVCServlet</servlet-name>
			<url-pattern>/c/*</url-pattern>
		</servlet-mapping>

 

上面主要有两个东西:

1.ContextLoaderListener 监听器:

2.DispatcherServlet  控制器:

 

在启动的时候,如果观察启动日志 就能发现,1.首先启动,2.然后是DispatcherServlet  ,我们来看看这两个东西 在初始化的时候干了什么?

 

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
        private ContextLoader contextLoader;
        // 这是实现了ServletContextListener 监听,一个初始化方法  和一个销毁的方法
 	public void contextInitialized(ServletContextEvent event) {
                // 这里已经废弃,不用了,一直未null
		this.contextLoader = createContextLoader();
		if (this.contextLoader == null) {
			this.contextLoader = this;
		}
                // 主要看看初始化,他到底做了什么,进入源码分析
		this.contextLoader.initWebApplicationContext(event.getServletContext());
	}
	public void contextDestroyed(ServletContextEvent event) {
	// ....略
	}

}

 

  进入ContextLoader,找到initWebApplicationContext 方法:

  

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 这里只贴方法

// 先判断 是否已经加载过了
if (servletContext.getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
// ...
}

// 创建 WebApplicationContext 对象,详细的看 create 方法
if (this.context == null) {
		this.context = createWebApplicationContext(servletContext);
  }
// 这一步就是加载你xml 配置<context-param> 里面的内容,默认是application...
// 看后面他是如何实现的。
if (this.context instanceof ConfigurableWebApplicationContext) {
   
 configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext);

  }
 }
}

 

 

createWebApplicationContext 方法,负责创建 WebApplicationContext  上下文对象

 

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
// 这里拿到XmlWebApplicationContext 的对象
Class<?> contextClass = determineContextClass(sc);
// 这里转成他的扩展接口对象ConfigurableWebApplicationContext ,多加了一些获得配置信息的方法
// 至于这里一步的原因我不是很明白,大概是为了一个兼容的的问题,以前的设计这里会出错。
ConfigurableWebApplicationContext wac =
   
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  
return wac;
}

// 这个类默认创建指定处理xml/bean 的类对象
protected Class<?> determineContextClass(ServletContext servletContext) {
        // 这里表示你在web.xml 可以手动自己写一个需要处理的加载类对象,
	// 默认是XmlWebApplicationContext
        // 如何你需要额外的加载,一般是继承XmlWebApplicationContext 行了
	String contextClassName = servletContext.getInitParameter(
	CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
                        // 这里是默认是获得当前线程的加载器
			return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
		}
		else {  
                        // 这里是通过properties 进行加载,defaultStrategies 是一个静态类
			// 默认获得当前目录下ContextLoader.properties里面的XmlWebApplicationContext 类路径
			contextClassName = defaultStrategies.getProperty(
				WebApplicationContext.class.getName());
			try {
                        // 这里同样通过类路径装载类,加载器是ContextLoader
			return ClassUtils.forName(contextClassName,
			ContextLoader.class.getClassLoader());
			}
		}
}

 

  

    这里主要负责加载xml 文件

   

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {

// 这里官方解释 和EJB 有关系,具体请看API。类似我们这种纯web 中,这里一般都是空的
ApplicationContext parent = loadParentContext(sc);
// 这里就是加载我们配置的contextConfigLocation 的参数,这也是为什么需要这个名字的原因
// 同时里面所有对应的xml文件都会找到,对应的参数值是:
// classpath*:com/home/config/spring/spring-*.xml
String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (initParameter != null) {
			wac.setConfigLocation(initParameter);
		}
// 这里是定制自己的context,也就是你可以扩展,这里我是没扩展,所以没用,不解释
customizeContext(sc, wac);
// 这里方法,在子类 AbstractApplicationContext 里面
// 它负责加载xml properties 以及database schema ,看看他是如何操作的!
wac.refresh();

}
 

 

   refresh()方法

   

public void refresh() throws BeansException, IllegalStateException {
// 这里会更新当前操作的时间,以及操作状态,表示现在可以操作了。
prepareRefresh();
// 这里是实例化bean工厂,准备开始了,详细看下面
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
}
      
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
                // 初始化工厂,并获得配置的xml 指向的地址
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		return beanFactory;
	}
  

 

  

protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {  
                        // 创建新工厂
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
                        // 工厂加载对应的xml bean,接着看下面
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		}
	}

 

 这是XmlWebApplicationContext 里面的

// 加载初始化 设置的bean 信息
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

       		// 设置一些资源信息,为加载做准备
                beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// 执行加载
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

  

   // 具体的加载步骤,通过XmlBeanDefinitionReader 进行操作

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
// 这里会获得classpath*:....*.xml 等你配置的地址 		
String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			for (String configLocation : configLocations) {
				// 这里根据地址得到相对文件并进行加载
				// 主要通过PathMatchingResourcePatternResolver  解析获
				// 相对路径
				// 然后通过 XmlBeanDefinitionReader里面各种方法,
				// 最后 doLoadBeanDefinitions 进行处理xml 文件属性
				reader.loadBeanDefinitions(configLocation);
			}
		}
	}

 

     到现在为止,我们配置的xml bean文件已经加载完了,下面看看 bean 里面相关联的properties 文件如何加载的。继续回到AbstractApplicationContext   refresh()方法:

    

public void refresh() {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 这是准备bean 工厂,初始化一些工具类
prepareBeanFactory(beanFactory);

postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 加载的bean,
registerBeanPostProcessors(beanFactory);
// 初始化消息
initMessageSource();
// 初始化事件列表,或者监听,对加载的bean 的一些添加移除等操作进行管理
initApplicationEventMulticaster();

// 扩展的时候需要
onRefresh();
// 注册监听,并通过name 把所有的bean 放入进行管理
registerListeners();
// 把context 剩下的延迟加载的bean 加载完
finishBeanFactoryInitialization(beanFactory);
// 发布时间,对一些生命周期进行监控。 这个里面的方法 是主体方法,后面再分开研究吧。
finishRefresh();
}

 

  小结: 整个初始化步骤

          1.ContextLoaderListener  启动,开始调用初始化方法

          2.ContextLoader 具体执行初始化任务,主要创建上下文对象 WebApplicationContext

     2.1 读取一些配置配置文件路径,设置一些初始化参数

     3 XmlWebApplicationContext  xml 文件进行解析,封装成集合信息

          4.AbstractApplicationContext  把刚那些集合对象信息,进行基本的初始化 监听 发布等等操作,最后

我们的就能从上下文信息,里面取得我们想要的的信息了。

 

整个过程,只写了个大概,辅助了解,深入需要自己去看官方文档和源码,建议设计图结合看。 

分享到:
评论

相关推荐

    spring boot实战.pdf高清无水印

    1.2.2 使用Spring Initializr初始化Spring Boot项目 10 1.3 小结 18 第2章 开发第一个应用程序 19 2.1 运用Spring Boot 19 2.1.1 查看初始化的Spring Boot新项目 21 2.1.2 Spring Boot项目构建过程解析 ...

    spring源代码解析

    在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这个上下文体系的过程。Spring为web应用提供了上...

    Spring-Reference_zh_CN(Spring中文参考手册)

    3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.6.1. 设置Bean使自动装配失效 3.3.7. 依赖检查 3.3.8. 方法注入 3.3.8.1. Lookup方法注入 3.3.8.2. 自定义方法的替代方案 3.4. bean的作用域 3.4.1. ...

    spring chm文档

    3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.4. 自定义作用域 ...

    Spring中文帮助文档

    3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton beans和prototype-bean的...

    Spring 2.0 开发参考手册

    3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.4. 自定义作用域 ...

    Spring API

    3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton beans和prototype-bean的...

    Spring攻略(第二版 中文高清版).part1

    2.7 自定义Bean初始化和析构 72 2.7.1 问题 72 2.7.2 解决方案 72 2.7.3 工作原理 72 2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 ...

    Spring攻略(第二版 中文高清版).part2

    2.7 自定义Bean初始化和析构 72 2.7.1 问题 72 2.7.2 解决方案 72 2.7.3 工作原理 72 2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

    JAVA上百实例源码以及开源项目源代码

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    【毕业设计】基于SSM的实验室管理系统 .zip

    所有的请求都将被它拦截,并且在初始化该servlet的时候就将映射初始化进来,因此DispatchServlet可以返回映射之后的视图。 MyBatis MyBatis 是一个不错的持久层框架,减少了代码的硬编码,也支持用户自己编写SQL...

    JAVA上百实例源码以及开源项目

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    java8源码-LearnSpring:学习springboot

    java8 源码 Learn Spring Bean 注解 Target 关联注解 所在模块 所在包 ...事务(Transactional) ...MVC ...学习Spring的关键 ...注解就相当于在业务开发中的功能需求,重点是理解加上注解之后程序如何...容器初始化的工作。 sprin

    《程序天下:J2EE整合详解与典型案例》光盘源码

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

    EL表达式 (详解)

    因为我们并没有指定哪一个范围的username,所以它会依序从Page、Request、Session、 Application范围查找。 假如途中找到username,就直接回传,不再继续找下去,但是假如全部的范围都没有找到时, 就回传null。 ...

    Maven权威指南 很精典的学习教程,比ANT更好用

    Simple Weather源码 4.7. 添加资源 4.8. 运行Simple Weather项目 4.8.1. Maven Exec 插件 4.8.2. 浏览你的项目依赖 4.9. 编写单元测试 4.10. 添加测试范围依赖 4.11. 添加单元测试资源 4.12. 执行单元...

Global site tag (gtag.js) - Google Analytics