本文是对《Spring IOC 容器源码分析》 的总结,我对照这篇文章和 Spring 源码进行学习之后,精要化出一些结论。如果时间紧迫可以参考本篇文章,如果时间充裕,更建议对照那篇文章过一遍源码(那篇文章写于2017年,和最新的源码稍有一点点出入,没关系)。
我之前写过一篇介绍 IOC 概念的文章,现在回看想掐死自己……一副什么都不懂却特别跳的样子,气人。
这里重新简要写一下 IOC 的概念:IOC 是控制反转(Inversion of Control)的缩写,控制指的是“控制对象的获得”,比如当需要一个对象的时候,怎么获得这个对象:
常见的“控制”思路,是什么时候需要对象就什么时候 new 一个出来,对象没有创建就无法继续下去,“new 对象”控制了后续代码
“控制反转”的思路,是什么时候需要对象就什么时候向资源池要,因为代码需要,所以才向资源池要对象,后续代码控制了对象的获得。
细品一下“控制对象的获得”这几个字就能理解了,可以简单理解为先后顺序。如果先 new 对象再写后续代码,或者是工厂方法获得对象,等等,都使得获取过程要靠自身实现,代码高耦合不便于维护。所以 IOC 的思想是资源由资源池管理,需要的时候让第三方资源池提供。
在 Spring 中 IOC 向资源池要对象,资源池指的是 beanDefinitionMap
,这篇文章要学习的内容,就是 beanDefinitionMap
加载资源的初始化过程,也就是 Bean 读取和装载的过程。
(尽管现在使用 IOC 都是通过注解 @AutoWired,但本文仍以最原始的解析 xml 文件来展开。)
通过 ClassPathXmlApplicationContext
,将 xml 文件解析成一个个的 Bean,只需要一行代码:
1 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" );
这个构造方法实际上是在调用另一个构造方法:
1 2 3 public ClassPathXmlApplicationContext (String configLocation) throws BeansException { this (new String[] {configLocation}, true , null ); }
而这个构造方法的代码如下:
1 2 3 4 5 6 7 8 9 public ClassPathXmlApplicationContext (String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super (parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
创建 ClassPathXmlApplicationContext
,主要就是在调用 refresh()
方法,叫 refresh 的原因是它会销毁原来的 ApplicationContext,用以重建。这个方法海纳百川,内容量爆炸,我们只看前三个方法(足够理解 IOC 了):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); } }
我们今天的重点,是第二个方法创建 BeanFactory(obtainFreshBeanFactory()
),这个方法能往里扒快 20 层,主要功能是创建 BeanFactory、从 xml 文件中读取信息并解析成多个 BeanDefinition、把所有 Bean 注册到 beanDefinitionMap
中。
但是我们还是从第一个方法开始。
prepareRefresh() 记录时间、状态、校验数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 protected void prepareRefresh () { this .startupDate = System.currentTimeMillis(); this .closed.set(false ); this .active.set(true ); if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) { logger.trace("Refreshing " + this ); } else { logger.debug("Refreshing " + getDisplayName()); } } initPropertySources(); getEnvironment().validateRequiredProperties(); if (this .earlyApplicationListeners == null ) { this .earlyApplicationListeners = new LinkedHashSet<>(this .applicationListeners); } else { this .applicationListeners.clear(); this .applicationListeners.addAll(this .earlyApplicationListeners); } this .earlyApplicationEvents = new LinkedHashSet<>(); }
过。
obtainFreshBeanFactory() 这个方法会创建 Bean 工厂,注册 Bean,是最为重要的一个方法。
我在看博文和源码时,是边学习边截图代码用 PS 拼图的,本想把这部分代码整理成一张大图,结果里面有二十多个子方法,一层层剥进去十几层,PS 画布长八米多……因此用图片做直观学习是不太现实了。
本方法按顺序依次实现了下面这些内容:
销毁旧的所有 Bean,关闭旧的 BeanFactory
创建一个新的 BeanFactory
经过一系列步骤,读取 xml 配置文件
解析 Bean 定义,生成一个个的 BeanDefinition 的实例
根据名字,把所有的 Bean 注册在 beanDefinitionMap 里
注册事件等后续
按照顺序一点点把代码搬上来。
1. 销毁旧的 Bean 和 BeanFactory 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory(这里销毁的是当前 ApplicationContext 的旧 BeanFactory ,BeanFactory 是可以多个的)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } }
2. 创建一个新的 BeanFactory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected final void refreshBeanFactory () throws BeansException { try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); } catch (IOException ex) { throw new ... } }
创建的新的 BeanFactory 类型是 DefaultListableBeanFactory,createBeanFactory()
:
1 2 3 protected DefaultListableBeanFactory createBeanFactory () { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
BeanFactory 的继承关系如图(图片源于学习博文):
从继承关系可以看到,这个 DefaultListableBeanFactory 是所有 BeanFactory 的集大成者,实现了
可以获取多个 Bean(最顶层 BeanFactory 接口的方法都是获取单个 Bean 的)
可以将各个 BeanFactory 设置为父子关系
可以自动装配 Bean(Autowire)
在创建了一个 BeanFactory 之后,紧接着给它设置了三个属性(代码不贴了):
设置序列化 ID(使用 applicationContext 的 ID)
设置是否允许 BeanDefinition 覆盖
设置是否允许循环引用
BeanDefinition 覆盖的默认配置是:在同一配置文件中 Bean id 或 name 重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖。循环引用的意思是:A 依赖 B,而 B 依赖 A;或 A 依赖 B,B 依赖 C,而 C 依赖 A。
3. 经过一系列步骤,读取 xml 配置文件 这块我都不想贴代码了,一系列步骤的意思就是一系列步骤,往里扒到吐血的那种。
总体上走了这些流程(这些都是指读取 xml 数据):
创建一个 XmlBeanDefinitionReader 并设置参数,用于读取 xml 数据
读取 Resource[] 资源数组,遍历逐一处理
把 Resource 包装成 EncodedResource
创建一个 Set(ThreadLocal),逐一装入 EncodedResource,检查是否重复加入
将 EncodedResource 读出 InputStream,再转换成 InputSource
将 InputSource 转换成 Document(是 w3c 定义的接口,代表着 xml 的节点)
创建 DocumentReader,用以解析 Document(实际上是解析 Document 中的 Element)。
DocumentReader 内部创建了 BeanDefinitionParserDelegate,用以负责解析 Bean 定义
解析 Bean 定义(看下一部分),并最终将所有的 Bean (实际上是 BeanDefinition)都装入到 BeanFactory 的 beanDefinitionMap 中,这是一个 ConcurrentHashMap。
4. 解析 Bean 定义 在经过一系列的流程之后,终于将 xml 资源转换成一个个的 Element,这是 w3c 定义的类,在此对应着 xml 文件中的各个节点。
xml 文件中有很多类型的节点,比如 <bean />
、<import />
、<alias />
等。默认的 Element 只有四种:<import />
、<alias />
、<bean />
和 <beans />
,这是 xmlns="http://www.springframework.org/schema/beans"
定义的,也就是默认的命名空间(default namespace),如果想要解析别的类型,需要增加额外的命名空间。
解析这四种默认的 Element 是采用下面的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void parseDefaultElement (Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { doRegisterBeanDefinitions(ele); } }
我们只关注处理 <bean />
标签定义,也就是 processBeanDefinition()
方法。
这个方法实际上是把 xml 中的 bean 信息解析成 BeanDefinition,然后再包装成 BeanDefinitionHolder,最终注册到 BeanFactory 中的 beanDefinitionMap 中。
4.5 Bean 是什么 学习到这里要停一下,来探讨一下 Bean 到底是个什么东西。从代码层面上讲,Spring 中的 Bean,可以简单认为是 BeanDefinition 的实例,BeanDefinition 中保存了 Bean 的信息,比如 Bean 指向的是哪个类、是否是单例的、是否懒加载等等。
再梳理一下关系:
ApplicationContext 内部持有一个实例化的 BeanFactory(默认是 DefaultListableBeanFactory),以后所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的。
BeanFactory 也就是 Bean 容器,它存放着 Spring 中的所有 Bean,存放的方式是用一张 map 存所有的 BeanDefinition(Bean 定义),在 DefaultListableBeanFactory 类中有一个 beanDefinitionMap 变量,就是那张存放所有的 Bean 定义的 map。
1 2 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256 );
也就是说,解析 xml,实际上就是把 xml 中的所有 Bean 信息都转换成 BeanDefinition 实例,然后存储在 beanDefinitionMap 中。
来看一下 BeanDefinition 接口的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public interface BeanDefinition extends AttributeAccessor , BeanMetadataElement { String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; int ROLE_APPLICATION = 0 ; int ROLE_SUPPORT = 1 ; int ROLE_INFRASTRUCTURE = 2 ; void setParentName (@Nullable String parentName) ; String getParentName () ; void setBeanClassName (@Nullable String beanClassName) ; String getBeanClassName () ; void setScope (@Nullable String scope) ; String getScope () ; void setLazyInit (boolean lazyInit) ; boolean isLazyInit () ; void setDependsOn (@Nullable String... dependsOn) ; String[] getDependsOn(); void setAutowireCandidate (boolean autowireCandidate) ; boolean isAutowireCandidate () ; void setPrimary (boolean primary) ; boolean isPrimary () ; void setFactoryBeanName (@Nullable String factoryBeanName) ; String getFactoryBeanName () ; void setFactoryMethodName (@Nullable String factoryMethodName) ; String getFactoryMethodName () ; ... }
4. (继续)解析 Bean 定义 回来,来看通过解析 xml 得到的一个个 Element,是怎么转换成 BeanDefinition 实例的。
上面说到,从 Element 解析成 BeanDefinition 实际上是这个方法:
1 2 3 4 5 } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); }
跟进去看这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'" , ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
这个方法一共做了三件事:
把 Element 解析成 BeanDefinitionHolder
把 BeanDefinitionHolder 中的 BeanDefinition 加入到 Bean 容器的 map 中(注册 Bean)
发送事件
我们先只看第一步,把相关代码贴上来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 @Nullable public BeanDefinitionHolder parseBeanDefinitionElement (Element ele, @Nullable BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0 ); if (logger.isTraceEnabled()) { logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases" ); } } if (containingBean == null ) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null ) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null ) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this .readerContext.getRegistry(), true ); } else { beanName = this .readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this .readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isTraceEnabled()) { logger.trace("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]" ); } } catch (Exception ex) { error(ex.getMessage(), ele); return null ; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null ; } @Nullable public AbstractBeanDefinition parseBeanDefinitionElement ( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this .parseState.push(new BeanEntry(beanName)); String className = null ; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null ; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this .readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found" , ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found" , ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing" , ele, ex); } finally { this .parseState.pop(); } return null ; }
代码很长很繁琐,将 Element 中的信息转换成了 BeanDefinition,其中最重要的是设置 BeanDefinition 的 beanName,也就是 Bean 的 ID。
至此,xml 中的一个节点,就被解析成了一个 BeanDefinition 实例(是一个)。
5. 注册 Bean 到 beanDefinitionMap 里 当获取到一个 BeanDefinition 实例之后,需要把这个实例注册到 Bean 容器里,也就是加入到 BeanFactory 中的 beanDefinitionMap 里。
这一步发生在从 Element 解析到 BeanDefinition 的第二步(往上翻 processBeanDefinition()
方法,没多远),也就是说,注册 Bean 实际上是在解析 xml 时一并完成的,刚获取到一个 BeanDefinition 实例,就直接把这个实例加入到 beanDefinitionMap 里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 public static void registerBeanDefinition ( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if (aliases != null ) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } } @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); } } BeanDefinition existingDefinition = this .beanDefinitionMap.get(beanName); if (existingDefinition != null ) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]" ); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]" ); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]" ); } } this .beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { synchronized (this .beanDefinitionMap) { this .beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this .beanDefinitionNames.size() + 1 ); updatedDefinitions.addAll(this .beanDefinitionNames); updatedDefinitions.add(beanName); this .beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { this .beanDefinitionMap.put(beanName, beanDefinition); this .beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this .frozenBeanDefinitionNames = null ; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } }
prepareBeanFactory(beanFactory) 看不太明白,抄一下代码和注释吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 protected void prepareBeanFactory (ConfigurableListableBeanFactory beanFactory) { beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this , getEnvironment())); beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this )); 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.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this ); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this ); beanFactory.registerResolvableDependency(ApplicationContext.class, this ); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this )); if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
到此为止,我们看完了 refresh()
的三个方法,Spring 已经解析并注册了所有 Bean,设置好了 BeanFactory,但是还没有真正实例化 Bean,创建 Bean 实例在 finishBeanFactoryInitialization()
方法中完成,本篇就先不继续学习了,到此为止。