`
greemranqq
  • 浏览: 977062 次
  • 性别: 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  把刚那些集合对象信息,进行基本的初始化 监听 发布等等操作,最后

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

 

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

分享到:
评论

相关推荐

    跟我学spring3-源码.

    《跟我学Spring3-源码》教程是一份深入解析Spring框架3.x版本核心源码的教育资源,适合对Java和J2EE技术有一定基础的开发者学习。本教程旨在帮助读者理解Spring框架的工作原理,提高在实际项目中的应用能力。通过...

    spring mvc step by step,例子

    1. **项目初始化**:可以使用Spring Initializr或者Maven Archetype来快速创建一个包含基本依赖的Spring MVC项目。 2. **配置Spring MVC**:在`web.xml`中配置`DispatcherServlet`,并添加Spring MVC的配置文件,如`...

    spring mvc 4.0

    14. **性能优化**:Spring MVC 4.0在内部做了许多性能优化,包括更快的DispatcherServlet初始化、更高效的HTTP方法映射等。 15. **兼容性与兼容性测试**:Spring MVC 4.0确保与各种Web容器的兼容性,如Tomcat、...

    Spring MVC源码深度剖析开源架构源码2021.pdf

    对Spring MVC源码的深入剖析不仅有助于开发者更好地理解框架的工作机制,而且可以为开发定制化组件、性能优化及故障排查等提供坚实的知识基础。通过学习和实践,开发者可以更有效地利用Spring MVC框架来构建高性能的...

    spring-mvc 基础功能之源码debug

    源码调试是学习Spring MVC的一个重要环节,它能帮助开发者理解框架内部的执行流程。通过设置断点,查看变量状态,跟踪方法调用,可以深入理解Spring MVC如何处理请求、如何进行依赖注入以及如何与视图交互。这种能力...

    spider-mvc-源码.rar

    《Spider-MVC 源码解析》 Spider-MVC 是一个基于Java的轻量级Web框架,它借鉴了MVC(Model-View-Controller)设计模式的理念,旨在简化Web应用程序的开发过程。通过分析Spider-MVC的源码,我们可以深入理解其内部...

    spring mvc-3.1.1与logback-1.0.3,slf4j-1.6.4集成

    这些类是自定义配置器,用于在Spring MVC启动时初始化Logback日志系统。`LogbackWebConfigurer`通常会在Web应用程序上下文中执行配置,确保Logback能够正确地读取和解析日志配置文件。`LogbackConfigurer`可能是一个...

    Spring MVC启动时初始化的几个常用方法

    在Spring MVC框架中,应用程序启动时会执行一系列初始化操作,这些操作对于理解Spring MVC的工作原理至关重要。本篇文章将深入探讨Spring MVC启动时初始化的几个常用方法,并解释它们在实际开发中的作用。 首先,...

    spring-boot源码

    它负责初始化Spring的ApplicationContext,并加载`src/main/resources/application.properties`或`application.yml`中的配置。`run()`方法是启动应用的主要入口。 4. **Actuator**:Spring Boot Actuator提供了多种...

    spring源码合集spring源码合集

    7. **Bean生命周期源码解析**:"05-Spring之Bean生命周期源码解析下-周瑜"将详细阐述Bean从创建到销毁的整个过程,包括初始化、后置处理、正常运行和销毁等阶段,使我们能更好地控制和管理Bean的状态。 8. **模拟...

    Spring-4.3源码

    另外,`@Lazy`注解用于延迟初始化bean,直到真正被请求时才会创建。 在Web层,Spring MVC是Spring框架的重要组件。Spring 4.3对MVC进行了优化,包括更好的类型安全的模型绑定、增强的异常处理和视图解析。`@...

    spring-2.5.6源码

    Spring管理Bean的生命周期,包括实例化、初始化、配置、使用和销毁。2.5.6版本支持Bean的生命周期回调方法,如初始化方法(init-method)和销毁方法(destroy-method),以及自定义的生命周期处理器。 五、Spring的...

    spring源码-2022-08-14spring源码spring源码spring源码

    - **依赖注入**:Spring如何通过XML、注解或Java配置实现bean的创建、初始化和装配。 - **AOP代理**:Spring如何使用JDK动态代理和CGLIB来实现AOP代理,以及切点表达式和通知的工作原理。 - **事件驱动**:Spring中...

    Spring源码深度解析第二版

    Bean的生命周期包括了Bean的创建、初始化和销毁等过程。依赖注入是指容器将Bean的依赖项注入到Bean中。AOP是指容器提供的面向切面编程功能。 2.3 工程搭建 为了使用Spring框架的容器,我们需要搭建工程环境。工程...

    【面试资料】-(机构内训资料)看透Spring MVC源代码分析与实践.zip

    这份【面试资料】-(机构内训资料)看透Spring MVC源代码分析与实践.zip文件很可能是为了帮助求职者准备相关面试问题而设计的,包含了对Spring MVC工作原理、关键组件和源码解读的详尽解析。 1. **Spring MVC基本...

    Servlet,JSP和Spring MVC 初学指南源码

    Spring MVC是Spring框架的一部分,是一个轻量级的MVC框架,用于构建高性能、可测试的Web应用程序。它简化了模型-视图-控制器的设计模式实现,通过DispatcherServlet进行请求分发,Controller处理请求,Model存储数据...

    Spring MVC Beginner’s Guide 源代码

    - **web.xml**:配置DispatcherServlet,定义Spring MVC的初始化参数。 - **servlet-context.xml**:Spring MVC的核心配置文件,声明拦截器、视图解析器、bean等。 3. **处理器映射器与适配器** - **...

    spring mvc项目后端源码

    19. **Spring Boot**:Spring MVC 常与 Spring Boot 结合使用,简化项目的初始化和配置。 这个"spring mvc项目后端源码"可能包含了上述部分或全部概念的实现,通过学习和分析这些代码,可以加深对 Spring MVC 框架...

    SSM(Spring +Spring MVC +Mybatis)源码

    在Spring中,通过XML配置或基于注解的配置,可以定义Bean的实例化、初始化、配置和它们之间的依赖关系。Spring还提供AOP(面向切面编程)功能,允许我们在不修改代码的情况下添加额外的功能,如日志记录、事务管理等...

    Spring-MVC简单项目

    4. **创建Spring配置**:创建一个或多个XML文件(如`spring-servlet.xml`),配置Spring MVC的各种组件,如视图解析器(ViewResolver)、模型-视图映射(HandlerMapping)、处理器适配器(HandlerAdapter)等。...

Global site tag (gtag.js) - Google Analytics