网上很多关键字针对了“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源码学习概述 Spring是Java生态系统中的一种流行的开源框架,由Rod Johnson创立于2003年。Spring框架的主要目标是使Java应用程序的开发变得更加简洁、灵活和可维护。Spring框架的核心思想是基于依赖注入...
本资料“Spring学习笔记&源码”是基于网易云课堂黑马程序员的Spring四天精通课程,旨在帮助学习者深入理解和实践Spring框架。 笔记部分可能会涵盖以下内容: 1. **Spring概述**:介绍Spring框架的历史、特点和主要...
spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文...
总之,Spring源码学习是一个深化编程技能,理解设计模式,以及提高问题解决能力的过程。通过深入研究,程序员不仅可以优化自己的代码,还能更高效地利用Spring框架提供的功能,提升项目的可维护性和扩展性。
"spring源码" 是指 Spring 框架的源代码。 部分内容解释 1. 下载 GitHub 客户端安装 下载 GitHub 客户端是因为 Spring 源码托管在 GitHub 上,所以我们需要下载 GitHub 客户端来 clone Spring 源码。安装成功后,...
Spring框架是Java开发中最广泛应用的轻量级框架之一,它以IoC(Inversion of Control,控制反转)和AOP...通过学习源码,我们可以更全面地掌握Spring框架,提升自己的技术水平,更好地应对各种复杂的软件开发挑战。
Spring 源码注释中文版的提供,使得开发者能够更加深入地理解 Spring 的工作原理,无需经过复杂的编译过程,可以直接阅读源码注释来学习。 Spring 框架主要由以下几个关键模块组成: 1. **Core Container(核心...
1、spring 的整体架构 2、spring的基本实现(xml的加载原理、标签解析、bean加载) 3、容器扩展 4、ioc和aop 5、事务 6、springmvc 7、dispatcherServlet
学习Spring源码有助于深入理解其内部工作原理,例如bean的生命周期管理、AOP的实现、以及MVC的请求处理流程。这将有助于开发者更高效地利用Spring框架,编写出高质量、高性能的Java应用。通过分析源码,开发者还可以...
在Eclipse中构建Spring源码项目,可以帮助我们深入理解Spring的工作原理,从而更好地利用它来构建高效、可维护的Java应用。以下将详细阐述如何构建和探索Spring源码。 1. **获取源码** Spring源码可以从官方GitHub...
这份"spring源码(注释+测试版)"提供了Spring框架的源代码,带有注释和测试用例,对于开发者深入理解Spring的工作原理非常有帮助。 1. **spring-core**:这是Spring框架的基础模块,包含了核心的工具类和资源处理...
spring源码分析专题,源码分析视频,对spring的源码进行分析
在这个"Spring框架学习源码"中,我们将会探讨以下几个关键知识点: 1. **SpringBoot**:SpringBoot简化了Spring应用程序的初始搭建以及开发过程。它内置了Tomcat服务器,提供了一种默认的配置,使得开发者可以快速...
在本文中,我们将详细介绍如何使用 IDEA 和 Gradle 构建 Spring 源码环境,以便深入学习 Spring 源码。下面是具体的步骤和知识点总结。 一、下载 Spring 源码 下载 Spring 源码有两种方式:一种是直接下载 zip ...
struts+hibernate+spring源码学习:hr考勤管理系统.rar
马士兵老师是知名的Java教育专家,他的Spring框架学习笔记深入浅出,对于初学者和进阶者来说都是一份宝贵的资源。这份笔记涵盖了Spring的核心概念、配置、AOP(面向切面编程)、DI(依赖注入)等关键知识点。 1. **...
通过深入阅读和分析Spring源码,不仅可以提升我们的技术能力,还能培养我们对软件设计原则和模式的理解,为成为一名更优秀的开发者奠定基础。Tom老师的这份资料无疑是一份宝贵的资源,它将引导我们逐步揭开Spring的...
总的来说,"Spring源码解析"这个压缩包为我们提供了一个系统性学习Spring源码的途径。通过深入学习和理解Spring的IoC、AOP以及事务管理的源码,我们可以提升对Spring框架的掌握程度,进而提高我们的开发能力和问题...
深入学习Spring源码,不仅能够理解其设计理念,还能提高问题定位和性能优化的能力。对于希望成为高级Java开发者或Spring专家的人来说,这是一个不可或缺的学习资源。官网资源通常会包含最新的文档、API参考以及示例...
在Spring框架的开发和学习过程中,...对于Spring源码的深入学习,了解其内部的工作原理,包括AOP、IOC(Inversion of Control)容器以及对其他库如CGlib和Objenesis的使用,都能极大地提升我们的技能和解决问题的能力。