`
j小虫
  • 浏览: 18826 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

spring源码学习(一)

    博客分类:
  • java
 
阅读更多

    网上很多关键字针对了“spring源码阅读”,但仔细的查看了很多,发现大部分都是一样的,而且讲得很粗,可以借鉴这些思路.但粗粗的去读一下这些文章,对spring真正的实现,还是比较迷茫的,要想真正了解spring,还是得仔细的研读它的每一行代码,对照着别人的思路,静下心来,反复看,才能一点一点的去理解它。有些关键字在百度上讨论得很少的关键字,比如:“EntityResolver”,“PropertySource”,"propertyResolver"之类的,很多人的博文略提到了一点,但也是匆匆而过,这些,都需要自己去看document,自己去看代码,自己去想。

 

  首先,从哪里开始读,我们的web工程要用到spring,必须在web的配置中引入spring的框架,那么,首先就需要去web.xml里找。contextLoaderListener正是我们要找的答案,同样的道理,log4j等等这些框架,也是在这里进行配置,我们通过listener的方式去引入它

 

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:spring/applicationcontext.xml,
			classpath*:spring/spring-*.xml,
			classpath*:spring/consumer/spring-*.xml,
			classpath*:spring/provider/spring-*.xml	
		</param-value>
	</context-param>
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/WEB-INF/log4j.properties</param-value>
	</context-param>
	<context-param>
		<param-name>log4jRefreshInterval</param-name>
		<param-value>60000</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
 这里可以看到,我们用到了spring的web包下的contextLoaderListener来作为整个spring容器加载的入口,这里,要稍微提一下,读spring的任何源码的时候,最好刻意的,让自己去看一下他的包路径,对理解它整个框架的划分,慢慢的会有一些好处。  下面,我们来看看contextLoaderListener.
 
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
 从ServletContextListener继承而来,ServletContextListener是servlet包下的接口
	/** 
	 * Implementations of this interface receive notifications about
	 * changes to the servlet context of the web application they are
	 * part of.
	 * To receive notification events, the implementation class
	 * must be configured in the deployment descriptor for the web
	 * application.
	 * @see ServletContextEvent
	 * @since	v 2.3
	 */

        public interface ServletContextListener extends EventListener {
	/**
	 ** Notification that the web application initialization
	 ** process is starting.
	 ** All ServletContextListeners are notified of context
	 ** initialization before any filter or servlet in the web
	 ** application is initialized.
	 */

    public void contextInitialized ( ServletContextEvent sce );

	/**
	 ** Notification that the servlet context is about to be shut down.
	 ** All servlets and filters have been destroy()ed before any
	 ** ServletContextListeners are notified of context
	 ** destruction.
	 */
    public void contextDestroyed ( ServletContextEvent sce );
 可以看到,他有一个contextInitialized方法,这个方法在启动初始化时回调,因此,在contextLoaderListener中,找到这个方法的实现,就是我们需要的地方
public void contextInitialized(ServletContextEvent event) {
		this.contextLoader = createContextLoader();
		if (this.contextLoader == null) {
			this.contextLoader = this;
		}
		this.contextLoader.initWebApplicationContext(event.getServletContext());
	}
 
好了,前4行代码忽略,createContextLoader()在spring2.5以后,变成了空实现,里面啥也没干,直接进入
contextLoader.initWebApplicationContext.   在进入之前,我们对它的名字思考一下,顾名思义, contextLoaderListner中有一个contextLoader对象,我们用它去初始化WebApplicationContext.用一个ServletContext作为参数,这里要先强调一下,读spring的代码,一定要注意它的一些抽象概念,比如context,ServletContext,Reader,Bean,这种名词,当你全部理解了这些名词的时候,你也就真的懂了
 
这里我们用到了这两个:
1.contextLoader:   读取器,用来读context的读取器,context是spring中一个非常重要的概念,我们可以简单的 理解为容器,如ApplicationContext.
2.ServletContext:   servlet上下文,我们在很多时候写代码都需要一些贯穿始终的参数,在servlet环境中,web容器就是利用servletContext来作为一个参数进行传递,后续我们还会读到spring中的一些比如holder. propertySources等概念,也是这个用途
3.WebApplicationContext:  web环境的spring容器,是容器的一种
 
接下来,进入initWebApplicationContext方法
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		Log logger = LogFactory.getLog(ContextLoader.class);
		servletContext.log("Initializing Spring root WebApplicationContext");
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext);
			}
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;
			}
			else if (ccl != null) {
				currentContextPerThread.put(ccl, this.context);
			}

			if (logger.isDebugEnabled()) {
				logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
						WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
			}
			if (logger.isInfoEnabled()) {
				long elapsedTime = System.currentTimeMillis() - startTime;
				logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
			}

			return this.context;
		}
		catch (RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
		catch (Error err) {
			logger.error("Context initialization failed", err);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
			throw err;
		}
	}
 我们看前3行,可以根据字面意思猜到,容器不能重复定义或重复加载,而且,容器创建好之后会放在ServletContext这个上下文中,并且key是一个常量,等会看到最后我们来验证这个猜测。
 
紧接着一堆日志,开始时间,这些我们都不关注
真正的加载代码,从try开始
this.context = createWebApplicationContext(servletContext);
这行字面意思是,创建一个web环境的容器,接着
if (this.context instanceof ConfigurableWebApplicationContext) {
				configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext);
			}
表示创建的web环境的容器,必须是configurable的,可配置的,假如是可配置的,就执行配置+刷新操作。
至于为什么可配置,怎么配置,什么叫配置,我们待会应该能看懂。
 
再往下
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
 验证了我们之前的猜测,容器创建好之后放到servlet的上下文中
 
再后面的几行代码,我们就不用去关心了,至此,spring容器加载的最重要3步就是:
1.创建一个web applicationcontext,
2.配置并且刷新bean
3.把刷新好的context放到servlet上下文中去。
 
有了这三步,我们再去逐一的看看,他们分别是怎么实现的。后续还会遇到很多名词,在spring中,这些名词都有很深刻的含义,了解了这些名词才能深刻的了解spring,在(二)中我们去学习创建webApplicationContext.
 
 
 

 

 

 

分享到:
评论

相关推荐

    Spring源码学习一:源码分析概述1

    Spring源码学习概述 Spring是Java生态系统中的一种流行的开源框架,由Rod Johnson创立于2003年。Spring框架的主要目标是使Java应用程序的开发变得更加简洁、灵活和可维护。Spring框架的核心思想是基于依赖注入...

    Spring学习笔记&源码

    本资料“Spring学习笔记&源码”是基于网易云课堂黑马程序员的Spring四天精通课程,旨在帮助学习者深入理解和实践Spring框架。 笔记部分可能会涵盖以下内容: 1. **Spring概述**:介绍Spring框架的历史、特点和主要...

    Spring源码学习加注释,方便学习.zip

    spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文...

    Spring高级源码学习笔记.zip

    总之,Spring源码学习是一个深化编程技能,理解设计模式,以及提高问题解决能力的过程。通过深入研究,程序员不仅可以优化自己的代码,还能更高效地利用Spring框架提供的功能,提升项目的可维护性和扩展性。

    spring 源码环境搭建

    "spring源码" 是指 Spring 框架的源代码。 部分内容解释 1. 下载 GitHub 客户端安装 下载 GitHub 客户端是因为 Spring 源码托管在 GitHub 上,所以我们需要下载 GitHub 客户端来 clone Spring 源码。安装成功后,...

    spring 源码中文注释

    Spring框架是Java开发中最广泛应用的轻量级框架之一,它以IoC(Inversion of Control,控制反转)和AOP...通过学习源码,我们可以更全面地掌握Spring框架,提升自己的技术水平,更好地应对各种复杂的软件开发挑战。

    spring源码注释中文

    Spring 源码注释中文版的提供,使得开发者能够更加深入地理解 Spring 的工作原理,无需经过复杂的编译过程,可以直接阅读源码注释来学习。 Spring 框架主要由以下几个关键模块组成: 1. **Core Container(核心...

    Spring源码解析.zip

    总的来说,"Spring源码解析"这个压缩包为我们提供了一个系统性学习Spring源码的途径。通过深入学习和理解Spring的IoC、AOP以及事务管理的源码,我们可以提升对Spring框架的掌握程度,进而提高我们的开发能力和问题...

    spring源码学习之思维导图

    1、spring 的整体架构 2、spring的基本实现(xml的加载原理、标签解析、bean加载) 3、容器扩展 4、ioc和aop 5、事务 6、springmvc 7、dispatcherServlet

    spring源码

    学习Spring源码有助于深入理解其内部工作原理,例如bean的生命周期管理、AOP的实现、以及MVC的请求处理流程。这将有助于开发者更高效地利用Spring框架,编写出高质量、高性能的Java应用。通过分析源码,开发者还可以...

    构建为eclipse项目的spring源码

    在Eclipse中构建Spring源码项目,可以帮助我们深入理解Spring的工作原理,从而更好地利用它来构建高效、可维护的Java应用。以下将详细阐述如何构建和探索Spring源码。 1. **获取源码** Spring源码可以从官方GitHub...

    spring源码(注释+测试版)

    这份"spring源码(注释+测试版)"提供了Spring框架的源代码,带有注释和测试用例,对于开发者深入理解Spring的工作原理非常有帮助。 1. **spring-core**:这是Spring框架的基础模块,包含了核心的工具类和资源处理...

    spring源码分析专题学习资源

    spring源码分析专题,源码分析视频,对spring的源码进行分析

    spring框架学习源码

    在这个"Spring框架学习源码"中,我们将会探讨以下几个关键知识点: 1. **SpringBoot**:SpringBoot简化了Spring应用程序的初始搭建以及开发过程。它内置了Tomcat服务器,提供了一种默认的配置,使得开发者可以快速...

    idea+gradle构建spring源码环境.docx

    在本文中,我们将详细介绍如何使用 IDEA 和 Gradle 构建 Spring 源码环境,以便深入学习 Spring 源码。下面是具体的步骤和知识点总结。 一、下载 Spring 源码 下载 Spring 源码有两种方式:一种是直接下载 zip ...

    struts+hibernate+spring源码学习:hr考勤管理系统.rar

    struts+hibernate+spring源码学习:hr考勤管理系统.rar

    马士兵老师spring框架学习笔记

    马士兵老师是知名的Java教育专家,他的Spring框架学习笔记深入浅出,对于初学者和进阶者来说都是一份宝贵的资源。这份笔记涵盖了Spring的核心概念、配置、AOP(面向切面编程)、DI(依赖注入)等关键知识点。 1. **...

    Tom_深入分析Spring源码

    通过深入阅读和分析Spring源码,不仅可以提升我们的技术能力,还能培养我们对软件设计原则和模式的理解,为成为一名更优秀的开发者奠定基础。Tom老师的这份资料无疑是一份宝贵的资源,它将引导我们逐步揭开Spring的...

    spring 源码 官网资源

    深入学习Spring源码,不仅能够理解其设计理念,还能提高问题定位和性能优化的能力。对于希望成为高级Java开发者或Spring专家的人来说,这是一个不可或缺的学习资源。官网资源通常会包含最新的文档、API参考以及示例...

    spring源码报错缺失的两个包

    在Spring框架的开发和学习过程中,...对于Spring源码的深入学习,了解其内部的工作原理,包括AOP、IOC(Inversion of Control)容器以及对其他库如CGlib和Objenesis的使用,都能极大地提升我们的技能和解决问题的能力。

Global site tag (gtag.js) - Google Analytics