本章主要内容是由以下部分组成,
在学习源码的过程当中,我想强调两点:
启动容器,实际上指的就是实例化ApplicationContext的这个动作。只是在不同情况下可能有不同的表现形式。
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml");
@Configuration @ComponentScan("ric.study.demo.ioc") public class BeanDemoConfig { public static void main(String... strings) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanDemoConfig.class); System.out.println("Spring container started and is ready"); ... } }
类似前面这两种 new ***ApplicationContext
的方式,很少会用于直接的生产开发。一般都是我们自己在demo中或者单元测试中会用到。
这个实际上是我们平常最常用的初始化方式,Spring MVC 中 ServletContext 为 Spring 的 IoC容器提供了宿主环境。是通过ContextLoaderListener 的初始化来建立的。
WebApplicationContext 的初始化调用链路:ContextLoaderListener.contextInitialized --> ContextLoader.initWebApplicationContext --> ContextLoader.createWebApplicationContext --> ContextLoader.determineContextClass --> ContextLoader.determineContextClass。
底层是通过反射来实例化的。
protected WebApplicationContext createWebApplicationContext(ServletContext sc) { Class<?> contextClass = determineContextClass(sc); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); }
这块内容先简要提一下,属于SpringMVC的内容,不是我们今天要讲的Spring IoC 模块的知识。
现在让我们正式开始的源码解读。会从最经典的ClassPathXmlApplicationContext 上下文为起点,来描述整个过程。
在说明之前,我想了想还是觉得把整个IoC容器初始化的关键步骤为大家梳理一下,以便于大家能在心里有个大概的脉络,更容易读懂源码,更容易抓住重点。再重复提一句,看源码一定要学会抓重点,归纳核心类、核心方法、核心步骤。
ClassPathXmlApplicationContext 的容器初始化我们大致分为下面几步:
这里的Resource定位 是通过继承ResourceLoader 获得的,ResourceLoader代表了 加载资源的一种方式,正是策略模式的实现 。
前面说了,实例化这个上下文,就是在启动 IoC 容器。那我们肯定要从它的构造函数入手。
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
入参中的 configLocations
在这里就是你XML配置文件 的 classpath。
setConfigLocations(configLocations);
我这里不展开讲,内容不复杂,就是把一些带有占位符的地址解析成实际的地址。
再之后就是 refresh()
,我们说的容器初始化,就是在这里面进行的,这里取名为refresh, 是因为容器启动之后,再调用 refresh()
会刷新IoC 容器 。
这里先放上IoC容器初始化的时序图,方便理解,
@Override public void refresh() throws BeansException, IllegalStateException { // 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛 synchronized (this.startupShutdownMonitor) { // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符 prepareRefresh(); // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中, // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了, // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean // 这块待会会展开说 prepareBeanFactory(beanFactory); try { // 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口, // 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】 // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化 // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事 postProcessBeanFactory(beanFactory); // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法 invokeBeanFactoryPostProcessors(beanFactory); // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别 // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化 registerBeanPostProcessors(beanFactory); // 初始化当前 ApplicationContext 的 MessageSource,国际化不是重点,不展开 initMessageSource(); // 初始化当前 ApplicationContext 的事件广播器,这里也不展开了 initApplicationEventMulticaster(); // 从方法名就可以知道,典型的模板方法(钩子方法), // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前) onRefresh(); // 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过 registerListeners(); // 重点,重点,重点 // 初始化所有的 singleton beans //(lazy-init 的除外) finishBeanFactoryInitialization(beanFactory); // 最后,广播事件,ApplicationContext 初始化完成 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源 destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
我会从上述流程中,挑以下几个进行分析,
protected void prepareRefresh() { // 记录启动时间, // 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型 this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment initPropertySources(); // 校验 xml 配置文件 getEnvironment().validateRequiredProperties(); this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); }
关键是以下几步,
注意:这步完成后,Bean 并没有完成初始化,实际的实例并没有被创建。
源码位置: AbstractApplicationContext#obtainFreshBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等 refreshBeanFactory(); // 返回上一步刚刚创建的BeanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
源码位置: AbstractRefreshableApplicationContext#refreshBeanFactory()
protected final void refreshBeanFactory() throws BeansException { // 如果 ApplicationContext 已经加载过 BeanFactory,销毁所有的Bean,关闭BeanFactory // 注意点:应用中BeanFactory是可以有多个的,这里可不是说全局是否有BeanFactory // 而是说当前的ApplicationContext有没有BeanFactory! if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 初始化一个 DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); // 用于 BeanFactory 的序列化,一般人应该用不到吧... beanFactory.setSerializationId(getId()); // 下面是两个重点方法 // 设置 BeanFactory 的两个重要属性 // 是否允许 Bean 覆盖、是否允许循环引用 TODO 2.1 customizeBeanFactory(beanFactory); // 加载BeanDefinition到BeanFactory 单独拉出来讲 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
看到这里的时候,可以感觉到一个设计思路,ApplicationContext 继承自 BeanFactory,但是 它不应该被理解为 BeanFactory 的实现类,而是说其内部持有一个实例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的 。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
BeanDefinition 的覆盖问题可能会有开发者碰到这个坑,就是在配置文件中定义 bean 时使用了相同的 id 或 name, 默认情况下,allowBeanDefinitionOverriding 属性为 null(Boolean类型),如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖 。
看下这个方法的声明,
/** * Load bean definitions into the given bean factory, typically through * delegating to one or more bean definition readers. * @param beanFactory the bean factory to load bean definitions into * @throws BeansException if parsing of the bean definitions failed * @throws IOException if loading of bean definition files failed * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader */ protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException;
在ClassPathXmlApplicationContext 是按照解析XML的加载方式。看javadoc的描述,是通过 XmlBeanDefinitionReader
来载入Bean Definitions。
/** * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */ @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // 初始化Reader 不重要,看下这个方法的javadoc就很好理解了 initBeanDefinitionReader(beanDefinitionReader); // 真正重要的步骤!! // 用Reader去加载XML配置 loadBeanDefinitions(beanDefinitionReader); }
loadBeanDefinitions(beanDefinitionReader)
/** * Load the bean definitions with the given XmlBeanDefinitionReader. * 看这句注释:this method is just supposed to load and/or register bean definitions. */ protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { // 这个分支,通过路径名去获取Resource,会和上面的方法殊途同归 reader.loadBeanDefinitions(configLocations); } }
AbstractBeanDefinitionReader#loadBeanDefinitions(Resource... resources)
@Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { // 遍历解析XML文件,加载 BeanDefinition counter += loadBeanDefinitions(resource); } return counter; }
接下去的源码不细讲,这里载入分为两大步,
BeanDefinitionDocumentReader
这里我觉得核心知识点就是Spring Bean规则的解析,简单点来说,里面包含了我们在XML配置的那些信息,怎么解析成容器中 BeanDefinition的规则和步骤。这部分由于和主要流程关系不大,我就没贴源码解析了,会占掉很大的篇幅,影响阅读和理解。
在这因为Spring 的 Bean配置方式有很多,解析配置信息到BeanDefinition的实现方式也有很多,XML又是现在少用的方式,所以关于XML中的Spring Bean规则的解析的详细源码就先略过了。有兴趣的同学可以阅读《Spring 技术内幕》这本书或者其他的文章书籍。
虽然上面说了不讲XML 解析 成 BeanDefinition的过程源码。但是上述 loadBeanDefinitions(resource)
包含了我们关键的第三步,注册Bean。这部分还是需要填一下的。
注意一下前面实例化Reader的代码,
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); /** * Create new XmlBeanDefinitionReader for the given bean factory. * @param registry the BeanFactory to load bean definitions into, * in the form of a BeanDefinitionRegistry */ public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) { super(registry); }
beanDefinitionReader 获取到 beanFactory 的引用,这个引用会在beanDefinition 被加载完毕要注册的时候使用到。可以看到是因为 BeanDefinitionRegistry
这个接口,赋予了BeanFactory注册BeanDefinition的特性。
具体执行“注册Bean”这一动作的源码,按照上述 loadBeanDefinitions(resource)
方法一直走下去的话是在 DefaultBeanDefinitionDocumentReader#processBeanDefinition()
方法中,
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 注册Bean BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
源码位置 BeanDefinitionReaderUtils#registerBeanDefinition()
/** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. // 注册 String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. // 如果还有别名的,把别名全都注册一遍 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { // 到时候获取的时候,就是先把Alias转化成BeanName,再去获取对应的Bean registry.registerAlias(beanName, alias); } } }
上面的 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
,
源码位置 DefaultListableBeanFactory#registerBeanDefinition()
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } // 注意哦,这里是有关 “允许Bean覆盖” 的逻辑代码 // 记得这个配置 allowBeanDefinitionOverriding BeanDefinition oldBeanDefinition; // beanDefinitionMap 是存放所有BeanDefinition的容器 oldBeanDefinition = this.beanDefinitionMap.get(beanName); // not null 说明,有重复名称的bean if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { // 判断是否允许覆盖,不允许直接抛异常 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // 打下debug log...用框架定义的 Bean 覆盖用户自定义的 Bean if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { // 打下debug log...用新的 Bean 覆盖旧的 Bean if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { // 打下debug log...用同等的 Bean 覆盖旧的 Bean if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 覆盖了 this.beanDefinitionMap.put(beanName, beanDefinition); } else { // 判断是否有其他Bean已经开始初始化了 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) // 检测创建 Bean 阶段已经开启,需要对 beanDefinitionMap 进行并发控制 synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase // 最最最正常的分支 // 注册 到 容器中 this.beanDefinitionMap.put(beanName, beanDefinition); // 这是一个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字 this.beanDefinitionNames.add(beanName); // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean, // 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的 // 手动指的是通过调用以下方法注册的 bean : // registerSingleton(String beanName, Object singletonObject) // 这不是重点,解释只是为了不让大家疑惑。Spring 会在后面"手动"注册一些 Bean, // 如 "environment"、"systemProperties" 等 bean,我们自己也可以在运行时注册 Bean 到容器中的 this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
以上,只是 obtainFreshBeanFactory()
的内容,到这里,BeanFactory也算是实例化完成了。
这里还是来个分割线。因为接下去会讲refresh() 方法的后续步骤的知识点,我想读者同学在这里最好最好,回到 前面 refresh()
总述的部分,再看一下。(如果你是一边还打开着IDE,在对照阅读调试的话,回到最前面refresh() 方法,再继续往下)
此方法负责对BeanFactory进行一些特征的设置工作,这些特征在代码中都有体现。
/** * Configure the factory's standard context characteristics, * such as the context's ClassLoader and post-processors. * @param beanFactory the BeanFactory to configure */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. // BeanFactory 需要加载类,所以需要获得类加载器 // 设置当前ApplicationContext的类加载器 beanFactory.setBeanClassLoader(getClassLoader()); // 内含 Spel 解释器,暂时不重要 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 注册属性编辑器,暂时不重要 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. // 添加一个ApplicationContextAwareProcessor,主要针对实现了Aware接口的Bean // 延伸知识:在Spring中我们自己的bean可以通过实现EnvironmentAware等一系列Aware接口,获取到Spring内部的一些对象。 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 依赖解析忽略, 设置哪些接口在进行依赖注入的时候应该被忽略 // 通俗来说,下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们, // Spring 会通过其他方式来处理这些依赖。 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. /** * 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值, * 之前我们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行 * ApplicationContext 还继承了 ResourceLoader、ApplicationEventPublisher、MessageSource * 所以对于这几个依赖,可以赋值为 this,注意 this 是一个 ApplicationContext * 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean */ beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. // 这个 BeanPostProcessor 也很简单,在 bean 实例化后,如果是 ApplicationListener 的子类, // 这个postProcessor的作用就是将其添加到 listener 列表中,可以理解成:注册 事件监听器 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. // 这里涉及到特殊的 bean,名为:loadTimeWeaver,AspectJ相关内容 // 不是这里的重点,放过我 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. // Spring 的“智能”操作,会帮我们默认注册一些有用的Bean // 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } // 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个 if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } // 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个 if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
这里会负责初始化所有的 singleton beans。
Spring 会在这个阶段完成所有的 singleton beans 的实例化。
到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor
接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory)
方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 environment
、 systemProperties
等。
剩下的就是初始化 singleton beans 了,我们知道它们是单例的, 如果没有设置懒加载 ,那么 Spring 会在接下来初始化所有的 singleton beans。
源码位置: AbstractApplicationContext#finishBeanFactoryInitialization()
/** * Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. */ protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. // 初始化"conversionService"的bean,此接口用于类型之间的转化,不是重点,放过我,自己去看 if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Register a default embedded value resolver if no bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. // 就是为了解析注解的值,没啥重点 if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(new StringValueResolver() { @Override public String resolveStringValue(String strVal) { return getEnvironment().resolvePlaceholders(strVal); } }); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. // 前面说过的,不是这里的重点 String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { // 先初始化 LoadTimeWeaverAware 类型的bean getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. // 看方法名就知道了,冻结所有BeanDefinition的元数据了 // 没什么别的目的,因为到这一步的时候,Spring 已经开始预初始化 singleton beans 了, // 肯定不希望这个时候还出现 bean 定义解析、加载、注册。 beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. // 开始初始化,进来看吧,重点在里面 beanFactory.preInstantiateSingletons(); }
源码位置: DefaultListableBeanFactory#preInstantiateSingletons()
@Override public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } // copy 一个包含所有BeanName的集合副本 List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // 触发所有非懒加载的 singleton beans的初始化 for (String beanName : beanNames) { // Bean 可能有继承parent的关系,获取合并后的RootBeanDefinition // 这个知识点用的很少的 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 非抽象、非懒加载的singletons if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // FactoryBean知识点,不了解的看另一篇文章或者自己google if (isFactoryBean(beanName)) { // FactoryBean 会在 beanName前面加前缀"&" final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; // SmartFactoryBean, 非重点,没深入了解,放过我 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { // 正常的bean都到这里来了,重点哦,里面进行初始化了 // 调用链很复杂,单独拉出来讲,先继续 getBean(beanName); } } } // 前面流程走完,说明所有的非懒加载singletonBean 完成了初始化 // Trigger post-initialization callback for all applicable beans... // 看注释就懂了,如果我们定义的 bean 是实现了 SmartInitializingSingleton 接口的, // 那么在这里得到回调,忽略它吧。 for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { smartSingleton.afterSingletonsInstantiated(); return null; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
lazy-init
ApplicationContext 实现的默认行为就是在启动时将所有 singleton bean提前进行实例化。 提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的singleton bean。通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天) 。
有时候这种默认处理可能并 不是 你想要的。如果你不想让一个singleton bean 在ApplicationContext 实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。一个延迟初始化bean 将告诉IoC 容器是在启动时还是在第一次被用到时实例化。
需要说明的是, 如果一个bean被设置为延迟初始化,而另一个非延迟初始化的singleton bean 依赖于它,那么当ApplicationContext 提前实例化singleton bean时,它必须也确保所有上述singleton 依赖bean也被预先初始化,当然也包括设置为延迟实例化的bean。 因此,如果Ioc容器在启动的时候创建了那些设置为延迟实例化的bean的实例,你也不要觉得奇怪,因为那些延迟初始化的bean可能在配置的某个地方被注入到了一个非延迟初始化singleton bean里面。
以上,本文就是关于Spring IoC 容器初始化的主要内容。
Spring IoC 的设计中,Bean定义的解析和Bean的依赖注入,是两个独立的过程,前面所有内容讲的就是IoC容器的初始化,资源定位、载入以及解析BeanDefinition并且注册。
最后一步的实例化所有单例,引入了 getBean()
方法,这就是Spring IoC 依赖注入的入口。也是下节源码解读的主要内容。
另外说一句,上面的源码解析,肯定不会是完备的,只是提取了我认为重要的东西。
如有疏漏,敬请谅解和自己查阅相关资料学习。如果错误,敬请指正!
本文由博客一文多发平台 OpenWrite 发布!