前言 1 2 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml" ); User userEntity = (User) context.getBean("userEntity" );
通过 application.xml
定义一些Bean对象,在项目启动后会由Spring的Bean工厂进行管理。
这一切都要从 refresh
说起。
1 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
obtainFreshBeanFactory()
主要做了两件事:
创建了一个容器对象——DefaultListableBeanFactory
解析自定义的Bean对象(XML、注解等),设置到 beanDefinition
中
抽象流程
XML的解析过程: String
-> Resource[]
-> EncodedResource
->Document
->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 @Override protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); this .beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
refreshBeanFactory
首先会创建一个BeanFactory
对象,并做一些基础的配置,最后加载BeanDefinition
1 2 3 protected DefaultListableBeanFactory createBeanFactory () { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
DefaultListableBeanFactory
就是最终的BeanFactory
对象。
解析自定义Bean对象 refreshBeanFactory()
中有一个loadBeanDefinitions()
,初始化documentReader
对XML文件进行读取,最终得到BeanDefinitions
。
BeanDefinitions是什么?
虽然通过Reader
对象读取解析得到了BeanDefinitions
,但是它并不是真正意义上的Bean对象。
可以理解为是一个 XML 到 Bean 的一个中间状态,无论你的Bean通过什么方式定义只要你能解析为BeanDefinitions我都可以把他创建成一个Spring Bean。
loadBeanDefinitions 1 2 3 4 5 6 7 8 9 10 @Override protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); loadBeanDefinitions(beanDefinitionReader); }
loadBeanDefinitions
方法中创建了XmlBeanDefinitionReader
后续会通过Reader
对象对XML进行一个读取和解析。
并且loadBeanDefinitions
运用了重载,虽然还是那个名字但是参数发生了改变。参数从Bean工厂变成了Reader
1 2 3 4 5 6 7 8 9 10 11 12 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); } }
此处就要看你在new ClassPathXmlApplicationContext()
的时候参数传的是什么了,分别执行两个方法。
loadBeanDefinitions
需要注意的是,执行的方法虽然还是loadBeanDefinitions
但是已经执行的不是原来那个对象的方法了,此时到了AbstractBeanDefinitionReader
对象。
1 2 3 4 5 6 7 8 9 @Override public int loadBeanDefinitions (String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null" ); int count = 0 ; for (String location : locations) { count += loadBeanDefinitions(location); } return count; }
因为参数是一个字符串的数组,此处对数组进行遍历,对字符串的资源地址再次执行loadBeanDefinitions
方法。
返回结果是一个int,也就是对应的资源地址加载成功的Bean数量。
loadBeanDefinitions
随后经历数次loadBeanDefinitions
方法,直接跳过了…
doLoadBeanDefinitions
Spring源码中很多名字叫 doXXXX 的对象才是真正干活的对象。
1 2 3 4 5 6 7 8 9 10 11 try { Document doc = doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; }
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 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.isDebugEnabled()) { logger.debug("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; }
parseBeanDefinitions 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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); } }
对整个XML文件进行逐行变量
parseDefaultElement 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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></bean>
自然会执行processBeanDefinition
processBeanDefinition 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 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)); } }
registerBeanDefinition 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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); } } }
registerBeanDefinition 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Override public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { else { this .beanDefinitionMap.put(beanName, beanDefinition); this .beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this .frozenBeanDefinitionNames = null ; }
此时registerBeanDefinition
已经回到了DefaultListableBeanFactory
方法,正常执行来说主要会做如下操作:
将解析成功的Bean对象名称加到beanDefinitionNames
的列表中
将BeanName和BeanDefinition的键值对存放在beanDefinitionMap
中
至此,就将五花八门的自定义Bean解析为了BeanDefinition
,并存放在了BeanFactory
中,后续需要加载某个Bean
时只需要根据名称到map
中找到对应的BeanDefinition
即可,然后执行doCreateBean
方法。