下面将会是冗长的代码分析,记住,一定要自己打开源码来看,不然纯看文章是很累的。
第一步,我们肯定要从 ClassPathXmlApplicationContext
的构造方法说起。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { private Resource[] configResources; public ClassPathXmlApplicationContext (ApplicationContext parent) { super (parent); } ... public ClassPathXmlApplicationContext (String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super (parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } ... }
接下来,就是 refresh()
,这里简单说下为什么是 refresh()
,而不是 init()
这种名字的方法。因为 ApplicationContext
建立起来以后,其实我们是可以通过调用 refresh()
这个方法重建的,refresh()
会将原来的 ApplicationContext
销毁,然后再重新执行一次初始化操作。
往下看,refresh()
方法里面调用了那么多方法,就知道肯定不简单了,请读者先看个大概,细节之后会详细说。
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 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
下面,我们开始一步步来肢解这个 refresh() 方法。
创建 Bean 容器前的准备工作 这个比较简单,直接看代码中的几个注释即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected void prepareRefresh () { this .startupDate = System.currentTimeMillis(); this .closed.set(false ); this .active.set(true ); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this ); } initPropertySources(); getEnvironment().validateRequiredProperties(); this .earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); }
创建Bean容器,加载并注册Bean 我们回到 refresh()
方法中的下一行 obtainFreshBeanFactory()
。注意,这个方法是全文最重要 的部分之一,这里将会初始化 BeanFactory
、 加载 Bean 、注册 Bean 等等。
当然,这步结束后,Bean
并没有完成初始化。这里指的是 Bean
实例并未在这一步生成。
// AbstractApplicationContext.java
1 2 3 4 5 6 7 8 9 10 11 protected ConfigurableListableBeanFactory obtainFreshBeanFactory () { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
// AbstractRefreshableApplicationContext.java
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 @Override protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(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
了,ApplicationContext
继承自 BeanFactory
,但是它不应该被理解为 BeanFactory
的实现类,而是说其内部持有一个实例化的 BeanFactory
(DefaultListableBeanFactory)。以后所有的 BeanFactory
相关的操作其实是委托给这个实例来处理的。
我们说说为什么选择实例化 DefaultListableBeanFactory
?前面我们说了有个很重要的接口 ConfigurableListableBeanFactory
,它实现了 BeanFactory
下面一层的所有三个接口,我把之前的继承图再拿过来大家再仔细看一下:
我们可以看到 ConfigurableListableBeanFactory
只有一个实现类 DefaultListableBeanFactory
,而且实现类 DefaultListableBeanFactory
还通过实现右边的 AbstractAutowireCapableBeanFactory
通吃了右路。所以结论就是,最底下这个家伙 DefaultListableBeanFactory
基本上是最牛的 BeanFactory
了,这也是为什么这边会使用这个类来实例化的原因。
如果你想要在程序运行的时候动态往 Spring IOC
容器注册新的 bean
,就会使用到这个类。那我们怎么在运行时获得这个实例呢?
之前我们说过 ApplicationContext
接口能获取到 AutowireCapableBeanFactory
,就是最右上角那个,然后它向下转型就能得到 DefaultListableBeanFactory
了。
在继续往下之前,我们需要先了解 BeanDefinition
。我们说 BeanFactory 是 Bean 容器 ,那么 Bean
又是什么呢?这里的 BeanDefinition
就是我们所说的 Spring 的 Bean,我们自己定义的各个 Bean 其实会转换成一个个 BeanDefinition 存在于 Spring 的 BeanFactory 中。所以,如果有人问你 Bean 是什么的时候,你要知道 Bean 在代码层面上可以认为是 BeanDefinition
的实例。
BeanDefinition
中保存了我们的 Bean
信息,比如这个 Bean
指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等 。
我们来看下 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 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 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 (String parentName) ; String getParentName () ; void setBeanClassName (String beanClassName) ; String getBeanClassName () ; void setScope (String scope) ; String getScope () ; void setLazyInit (boolean lazyInit) ; boolean isLazyInit () ; void setDependsOn (String... dependsOn) ; String[] getDependsOn(); void setAutowireCandidate (boolean autowireCandidate) ; boolean isAutowireCandidate () ; void setPrimary (boolean primary) ; boolean isPrimary () ; void setFactoryBeanName (String factoryBeanName) ; String getFactoryBeanName () ; void setFactoryMethodName (String factoryMethodName) ; String getFactoryMethodName () ; ConstructorArgumentValues getConstructorArgumentValues () ; MutablePropertyValues getPropertyValues () ; boolean isSingleton () ; boolean isPrototype () ; boolean isAbstract () ; int getRole () ; String getDescription () ; String getResourceDescription () ; BeanDefinition getOriginatingBeanDefinition () ; }
这个 BeanDefinition
其实已经包含很多的信息了,暂时不清楚所有的方法对应什么东西没关系,希望看完本文后读者可以彻底搞清楚里面的所有东西。
这里接口虽然那么多,但是没有类似 getInstance() 这种方法来获取我们定义的类的实例,真正的我们定义的类生成的实例到哪里去了呢?别着急,这个要很后面才能讲到。
有了 BeanDefinition
的概念以后,我们再往下看 refreshBeanFactory() 方法中的剩余部分:
1 2 customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory);
虽然只有两个方法,但路还很长啊。。。
customizeBeanFactory(beanFactory) 比较简单,就是配置是否允许 BeanDefinition
覆盖、是否允许循环引用。
1 2 3 4 5 6 7 8 9 10 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 ,如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖。
循环引用也很好理解:A 依赖 B,而 B 依赖 A。或 A 依赖 B,B 依赖 C,而 C 依赖 A。
默认情况下,Spring
允许循环依赖,当然如果你在 A 的构造方法中依赖 B,在 B 的构造方法中依赖 A 是不行的。
很多人都希望禁止出现 Bean 覆盖,可是 Spring
默认是不同文件的时候可以覆盖的。之后的源码中还会出现这两个属性,读者有个印象就可以了。
加载 Bean: loadBeanDefinitions
接下来是最重要的 loadBeanDefinitions(beanFactory)
方法了,这个方法将根据配置,加载各个 Bean
,然后放到 BeanFactory
中。
读取配置的操作在 XmlBeanDefinitionReader
中,其负责加载配置、解析。
// AbstractXmlApplicationContext.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this .getEnvironment()); beanDefinitionReader.setResourceLoader(this ); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this )); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
现在还在这个类中,接下来用刚刚初始化的 Reader
开始来加载 xml
配置,这块代码读者可以选择性跳过,不是很重要。也就是说,下面这个代码块,读者可以很轻松地略过。
// AbstractXmlApplicationContext.java
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 protected void loadBeanDefinitions (XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null ) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null ) { reader.loadBeanDefinitions(configLocations); } } @Override public int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null" ); int counter = 0 ; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; } @Override public int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null" ); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet<EncodedResource>(4 ); this .resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this .resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } catch (... } public int registerBeanDefinitions (Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } @Override public void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; logger.debug("Loading bean definitions" ); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
经过漫长的链路,一个配置文件终于转换为一颗 DOM 树了,注意,这里指的是其中一个配置文件,不是所有的,读者可以看到上面有个 for
循环的。下面开始从根节点开始解析doRegisterBeanDefinitions:
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 protected void doRegisterBeanDefinitions (Element root) { BeanDefinitionParserDelegate parent = this .delegate; this .delegate = createDelegate(getReaderContext(), root, parent); if (this .delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return ; } } } preProcessXml(root); parseBeanDefinitions(root, this .delegate); postProcessXml(root); this .delegate = parent; }
preProcessXml(root)
和 postProcessXml(root)
是给子类用的钩子方法,鉴于没有被使用到,也不是我们的重点,我们直接跳过。
这接下来,看核心解析方法 parseBeanDefinitions(root, this.delegate) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 protected void parseBeanDefinitions (Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0 ; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
从上面的代码,我们可以看到,对于每个配置来说,分别进入到 parseDefaultElement(ele, delegate); 和 delegate.parseCustomElement(ele); 这两个分支了。parseDefaultElement(ele, delegate)
代表解析的节点是 <import />
、<alias />
、<bean />
、<beans />
这几个。
这里的四个标签之所以是 default
的,是因为它们是处于这个 namespace
下定义的:http://www.springframework.org/schema/beans
不熟悉 namespace
的读者请看下面贴出来的 xml
,这里的第二行 xmlns
就是咯。
1 2 3 4 5 6 <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://www.springframework.org/schema/beans" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire ="byName" >
而对于其他的标签,将进入到 delegate.parseCustomElement(element) 这个分支。
如我们经常会使用到的 <mvc />
、<task />
、<context />
、<aop />
等。这些属于扩展,如果需要使用上面这些 “非 default” 标签,那么上面的 xml
头部的地方也要引入相应的 namespace
和 .xsd
文件的路径,同时代码中需要提供相应的 parser
来解析,如 MvcNamespaceHandler
、TaskNamespaceHandler
、ContextNamespaceHandler
、AopNamespaceHandler
等。
假如读者想分析 <context:property-placeholder location="classpath:xx.properties" />
的实现原理,就应该到 ContextNamespaceHandler
中找答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://www.springframework.org/schema/beans" xmlns:context ="http://www.springframework.org/schema/context" xmlns:mvc ="http://www.springframework.org/schema/mvc" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd " default-autowire ="byName" >
回过神来,看看处理 default
标签的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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
解析 bean
标签。
下面是 processBeanDefinition 解析 <bean />
标签:
// DefaultBeanDefinitionDocumentReader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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)); } }
Bean的配置像下面这样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <bean id ="exampleBean" name ="name1, name2, name3" class ="com.javadoop.ExampleBean" scope ="singleton" lazy-init ="true" init-method ="init" destroy-method ="cleanup" > <constructor-arg type ="int" value ="7500000" /> <constructor-arg name ="years" value ="7500000" /> <constructor-arg index ="0" value ="7500000" /> <property name ="beanOne" > <ref bean ="anotherExampleBean" /> </property > <property name ="beanTwo" ref ="yetAnotherBean" /> <property name ="integerProperty" value ="1" /> </bean >
当然,除了上面举例出来的这些,还有 factory-bean
、factory-method
、<lockup-method />
、<replaced-method />
、<meta />
、<qualifier />
这几个,大家是不是熟悉呢?自己检验一下自己对 Spring
中 bean
的了解程度。
有了以上这些知识以后,我们再继续往里看怎么解析 bean 元素,是怎么转换到 BeanDefinitionHolder 的。
// BeanDefinitionParserDelegate
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 public BeanDefinitionHolder parseBeanDefinitionElement (Element ele) { return parseBeanDefinitionElement(ele, null ); } public BeanDefinitionHolder parseBeanDefinitionElement (Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); 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.isDebugEnabled()) { logger.debug("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.isDebugEnabled()) { logger.debug("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 ; }
然后,我们再看看怎么根据配置创建 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 59 60 public AbstractBeanDefinition parseBeanDefinitionElement ( Element ele, String beanName, BeanDefinition containingBean) { this .parseState.push(new BeanEntry(beanName)); String className = null ; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null ; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } 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 ; }
到这里,我们已经完成了根据 <bean />
配置创建了一个 BeanDefinitionHolder
实例。注意,是一个。
我们回到解析 <bean />
的入口方法:
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)); } }
大家再仔细看一下这块吧,我们后面就不回来说这个了。这里已经根据一个 <bean />
标签产生了一个 BeanDefinitionHolder
的实例,这个实例里面也就是一个 BeanDefinition
的实例和它的 beanName
、aliases
这三个信息,注意,我们的关注点始终在 BeanDefinition
上:
1 2 3 4 5 6 7 8 public class BeanDefinitionHolder implements BeanMetadataElement { private final BeanDefinition beanDefinition; private final String beanName; private final String[] aliases; ...
然后我们准备注册这个 BeanDefinition
,最后,把这个注册事件发送出去。
下面,我们开始说说注册 Bean 吧。
// BeanDefinitionReaderUtils
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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); } } }
别名注册的放一边,毕竟它很简单,我们看看怎么注册 Bean。
// DefaultListableBeanFactory
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 @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 oldBeanDefinition; oldBeanDefinition = this .beanDefinitionMap.get(beanName); if (oldBeanDefinition != null ) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription()... } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { } else if (!beanDefinition.equals(oldBeanDefinition)) { } else { } this .beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { 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 { this .beanDefinitionMap.put(beanName, beanDefinition); this .beanDefinitionNames.add(beanName); this .manualSingletonNames.remove(beanName); } this .frozenBeanDefinitionNames = null ; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
总结一下,到这里已经初始化了 Bean 容器
,<bean />
配置也相应的转换为了一个个 BeanDefinition
,然后注册了各个 BeanDefinition
到注册中心,并且发送了注册事件。