在(三)里我们已经进入了AbstractApplicationContext的刷新方法,refresh,代码如下
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
它由很多个步骤组成,我们在(四)中就研究
prepareRefresh
这个步骤,看看刷新的第一步做了什么
顾名思义,刷新前的预处理,处理了什么,我们点进去看一下
protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); synchronized (this.activeMonitor) { this.active = true; } if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties this.environment.validateRequiredProperties(); }
可以看到,这个方法里它产生了容器的开始时间,接着改了active状态,这里稍微要注意一下
synchronized (this.activeMonitor) { this.active = true; }
他在改状态的时候用activeMonitor加了锁,并且改了active的状态为true,作者这么写的用意一定是为了让active在后续的某个操作或某个判断中去使用,既然active = true是在容器启动的开始时改的,那么后续肯定是在一些需要判断容器是否启动了来的地方使用,我们可以认为它是容器的激活状态,后续在任何修改容器的激活状态的地方,也一定会用activeMonitor来加锁。
再往下,打印一行refresh的日志
if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); }
继续看
// Initialize any placeholder property sources in the context environment initPropertySources();
初始化propertySources,主意哈,这个propertySources不是一堆propertySource啊,而是一个容器
spring里有两个概念,一个是propertySource,一个是propertySources,后者不是简单的表示一堆前者,而是表示一个存放前者的容器。我之前也在强调,spring里有很多名词,我们都需要去熟悉它们,知道它们是干什么的。 这里稍微偏移了扩展一下,我们看看propertySource和PropertySources的源码
在core包下,我们找到propertySource
public abstract class PropertySource<T> { protected final Log logger = LogFactory.getLog(this.getClass()); protected final String name; protected final T source; /** * Create a new {@code PropertySource} with the given name and source object. */ public PropertySource(String name, T source) { Assert.hasText(name, "Property source name must contain at least one character"); Assert.notNull(source, "Property source must not be null"); this.name = name; this.source = source; }
从泛型和构造我们可以大致了解,propertySource,是一个用来存放property的keyValue的实体,构造表示,我拿任意类型的对象进来,都可以设置一个key,存在成员name上,然后把对象存放在成员source上,是不是很像一个Map.Entry<String,Object>对象呢。
这里稍微需要了解下他有2个静态内部类StubPropertySource和ComparisonPropertySource
StubPropertySource是Property的子类,用于充当存根,它的注释中提到实际的PropertySource的初始化工作,不能在容器创建之前进行,所以用存根来充当一个占位符,他用来占用一个预期的propertySource位置,等容器refresh的时候用来进行替换,替换后成一个真正的值
如果这段话不好理解,可以先稍微知道有这么个东西,它是一个变量,用来占着你的property的位置,等刷新的时候再进行填充。
ComparisonPropertySource是存根的子类,仅仅用于集合的操作。注释中也是这么说,我们在propertySource的named方法上按f2
Return a PropertySource implementation intended for collection comparison purposes only. Primarily for internal use, but given a collection of PropertySource objects, may be used as follows: List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>(); sources.add(new MapPropertySource("sourceA", mapA)); sources.add(new MapPropertySource("sourceB", mapB)); assert sources.contains(PropertySource.named("sourceA")); assert sources.contains(PropertySource.named("sourceB")); assert !sources.contains(PropertySource.named("sourceC"));
这里的集合比较不是简单的比较大小的意思,而 是一系列集合可比较的操作,如contains,equals等。
看完propertySource,我们再看propertySources
public interface PropertySources extends Iterable<PropertySource<?>> { /** * Return whether a property source with the given name is contained. * @param name the {@linkplain PropertySource#getName() name of the property source} to find */ boolean contains(String name); /** * Return the property source with the given name, {@code null} if not found. * @param name the {@linkplain PropertySource#getName() name of the property source} to find */ PropertySource<?> get(String name); }
可以看到,他是propertySource的一个容器接口,具备迭代能力,有2个容器级别的方法,contains和get,这都是集合中常见的概念,它只有一个实现类,MutablePropertySources
再看看MutablePropertySources
public class MutablePropertySources implements PropertySources { static final String NON_EXISTENT_PROPERTY_SOURCE_MESSAGE = "PropertySource named [%s] does not exist"; static final String ILLEGAL_RELATIVE_ADDITION_MESSAGE = "PropertySource named [%s] cannot be added relative to itself"; private final Log logger; private final LinkedList<PropertySource<?>> propertySourceList = new LinkedList<PropertySource<?>>();
他有一个propertySourceList,是用链表List来实现的,用于存放所有的propertySource,并且MutablePropertySources实现了contanins,get等集合方法,还有addFirst,addLast等添加对象的方法。在我们还没看到propertyResolver之前,先可以认为propertySource的检索都由容器自己完成,后续会看到一个全新的工具resolver,专门用于propertySources的检索,解析等相关工作
扯远了,回到容器刷新的第一步,initPropertySources方法来
@Override protected void initPropertySources() { super.initPropertySources(); WebApplicationContextUtils.initServletPropertySources( this.getEnvironment().getPropertySources(), this.servletContext, this.servletConfig); }
super的init是空实现,具体的初始化工作,直接由第2行开始
我们可以看到,initServletProperSources,顾名思义,就是初始化propertySources这个容器,那我们应该可以想到,它应该是往容器里塞点东西, 再看后面2个参数,一个是servletContext,一个servletConfig,那么我们知道了,它这个初始化,其实是想把servletContext,一个servletConfig这两个对象给存到容器的propertySources容器里去,我们点进去看看是不是和我们想得一样
public static void initServletPropertySources( MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) { Assert.notNull(propertySources, "propertySources must not be null"); if(servletContext != null && propertySources.contains(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) && propertySources.get(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) { propertySources.replace(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, new ServletContextPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext)); } if(servletConfig != null && propertySources.contains(SERVLET_CONFIG_PROPERTY_SOURCE_NAME) && propertySources.get(SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) { propertySources.replace(SERVLET_CONFIG_PROPERTY_SOURCE_NAME, new ServletConfigPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig)); } }
果然是这样,key是常量,value是一个PropertySource,
我们看下replace的实现,实现当然在propertySources的唯一一个实现类中,MutablePropertySources
/** * Replace the property source with the given name with the given property source object. * @param name the name of the property source to find and replace * @param propertySource the replacement property source * @throws IllegalArgumentException if no property source with the given name is present * @see #contains */ public void replace(String name, PropertySource<?> propertySource) { logger.debug(String.format("Replacing [%s] PropertySource with [%s]", name, propertySource.getName())); int index = assertPresentAndGetIndex(name); this.propertySourceList.set(index, propertySource); }
可以看到,他先用name查出这个propertySource的下标,然后进行替换
由于我们在之前容器里已经有servletContext了,那么现在servletContext就被propertySources接管了,它用replace方法,将servletContext存放了进来,key是一个常量,value是一个ServetPropertySource对象,ServetPropertySource就类似一个Entry.
读到这里我明白了,原来preRefresh预刷新,其实就是把记录一下开始时间,打印一下日志,然后把servletConfig和servletContext放到spring容器的propertySources容器里面.
好了,下一节我们一起去读refresh的第2步,
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
这一步里,spring开始使用Reader,Resource,Document,Registry,去解析配置文件,生成BeanDefinition,并且在注册器里进行注册,可以说,这一步,完成bean的读取解析的很重要的工作。
相关推荐
本资料“Spring学习笔记&源码”是基于网易云课堂黑马程序员的Spring四天精通课程,旨在帮助学习者深入理解和实践Spring框架。 笔记部分可能会涵盖以下内容: 1. **Spring概述**:介绍Spring框架的历史、特点和主要...
spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文注释方便学习,spring源码学习加注释。 spring源码中文...
总之,Spring源码学习是一个深化编程技能,理解设计模式,以及提高问题解决能力的过程。通过深入研究,程序员不仅可以优化自己的代码,还能更高效地利用Spring框架提供的功能,提升项目的可维护性和扩展性。
1、spring 的整体架构 2、spring的基本实现(xml的加载原理、标签解析、bean加载) 3、容器扩展 4、ioc和aop 5、事务 6、springmvc 7、dispatcherServlet
本压缩包包含了Spring的源码,对于理解Spring的工作原理、深入学习和优化自己的项目具有极大的帮助。 源码分析: 1. **IoC容器**:Spring的核心是IoC容器,它负责管理对象的生命周期和依赖关系。通过XML配置文件或...
"spring源码" 是指 Spring 框架的源代码。 部分内容解释 1. 下载 GitHub 客户端安装 下载 GitHub 客户端是因为 Spring 源码托管在 GitHub 上,所以我们需要下载 GitHub 客户端来 clone Spring 源码。安装成功后,...
Spring框架是Java开发中最广泛应用的轻量级框架之一,它以IoC(Inversion of Control,控制反转)和AOP...通过学习源码,我们可以更全面地掌握Spring框架,提升自己的技术水平,更好地应对各种复杂的软件开发挑战。
Spring 源码注释中文版的提供,使得开发者能够更加深入地理解 Spring 的工作原理,无需经过复杂的编译过程,可以直接阅读源码注释来学习。 Spring 框架主要由以下几个关键模块组成: 1. **Core Container(核心...
在Eclipse中构建Spring源码项目,可以帮助我们深入理解Spring的工作原理,从而更好地利用它来构建高效、可维护的Java应用。以下将详细阐述如何构建和探索Spring源码。 1. **获取源码** Spring源码可以从官方GitHub...
学习Spring源码有助于深入理解其内部工作原理,例如bean的生命周期管理、AOP的实现、以及MVC的请求处理流程。这将有助于开发者更高效地利用Spring框架,编写出高质量、高性能的Java应用。通过分析源码,开发者还可以...
Spring源码学习概述 Spring是Java生态系统中的一种流行的开源框架,由Rod Johnson创立于2003年。Spring框架的主要目标是使Java应用程序的开发变得更加简洁、灵活和可维护。Spring框架的核心思想是基于依赖注入...
这份"spring源码(注释+测试版)"提供了Spring框架的源代码,带有注释和测试用例,对于开发者深入理解Spring的工作原理非常有帮助。 1. **spring-core**:这是Spring框架的基础模块,包含了核心的工具类和资源处理...
spring源码分析专题,源码分析视频,对spring的源码进行分析
《Spring源码解析》 ...通过对Spring源码的深入学习,不仅可以提高我们对Spring的理解,还能提升解决问题的能力,为实际开发提供强大的支持。Spring源码的世界广阔且深邃,每一次探索都会带来新的收获。
四、导入 Spring 源码到 IDEA 在 Spring 源码目录下,有一个名为 `import-into-idea.md` 的文件,该文件提供了将 Spring 源码导入 IDEA 的步骤。我们可以按照该文件中的步骤,一步步完成导入过程。 五、编译和构建...
"Spring源码雷神"可能指的是对Spring框架深入源码级别的理解和解析。以下将详细阐述Spring框架的一些核心知识点: 1. **IoC(Inversion of Control)控制反转**:Spring的核心特性之一,它通过依赖注入(Dependency...
在这个"Spring框架学习源码"中,我们将会探讨以下几个关键知识点: 1. **SpringBoot**:SpringBoot简化了Spring应用程序的初始搭建以及开发过程。它内置了Tomcat服务器,提供了一种默认的配置,使得开发者可以快速...
接下来,我们将围绕Spring框架、Spring 4.x版本的关键特性以及如何通过源码学习进行详细的讨论。 Spring框架是Java企业级应用开发的核心工具,由Rod Johnson创建,它提供了一个全面的编程和配置模型,旨在简化Java...
马士兵老师是知名的Java教育专家,他的Spring框架学习笔记深入浅出,对于初学者和进阶者来说都是一份宝贵的资源。这份笔记涵盖了Spring的核心概念、配置、AOP(面向切面编程)、DI(依赖注入)等关键知识点。 1. **...
摘自javaEye 学习spring 源码的必备资料. 多多下载