refresh这个方法包含了整个BeanFactory初始化的过程,定位资源由obtainFreshBeanFactory()来完成,
[java] view plaincopy
PRotected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
可以看到其调用了refreshBeanFactory(),refreshBeanFactory()在这个类中是抽象方法,其实现在AbstractRefreshableapplicationContext中。
[java] view plaincopy
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) { …… } }
在这个方法中,先判断BeanFactory是否存在,如果存在则先销毁beans并关闭beanFactory,接着创建DefaultListableBeanFactory,并调用loadBeanDefinitions(beanFactory)装载bean定义。loadBeanDefinitions方法同样是抽象方法,是由其子类实现的,也即在AbstractxmlApplicationContext中。
[java] view plaincopy
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { <span style="color:#33ff33;"> // 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件</span> XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); <span style="color:#33ff33;">//这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的</span> <span style="color:#33ff33;"> //因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader </span> beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); <span style="color:#33ff33;">//这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理</span> loadBeanDefinitions(beanDefinitionReader); }
接着我们转到beanDefinitionReader中进行处理
[java] view plaincopy
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { <span style="color:#33ff33;"> //调用XmlBeanDefinitionReader来载入bean定义信息。</span> reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
可以到org.springframework.beans.factory.support看一下BeanDefinitionReader的结构
在其抽象父类AbstractBeanDefinitionReader中定义了载入过程
[java] view plaincopy
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { <span style="color:#33ff33;"> //这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader </span> ResourceLoader resourceLoader = getResourceLoader(); <span style="color:#33ff33;">//如果没有找到我们需要的ResourceLoader,直接抛出异常</span> if (resourceLoader instanceof ResourcePatternResolver) { <span style="color:#33ff33;">// 这里处理我们在定义位置时使用的各种pattern,需要 ResourcePatternResolver来完成</span> try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); return loadCount; } ........ } else { <span style="color:#33ff33;">// 这里通过ResourceLoader来完成位置定位</span> Resource resource = resourceLoader.getResource(location); <span style="color:#33ff33;"> // 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader来使用了</span> int loadCount = loadBeanDefinitions(resource); return loadCount; } }
看到第8、16行,结合上面的ResourceLoader与ApplicationContext的继承关系图,可以知道此时调用的是DefaultResourceLoader中的getSource()方法定位Resource,因为ClassPathXmlApplicationContext本身就是DefaultResourceLoader的实现类,所以此时又回到了ClassPathXmlApplicationContext中来。
继续回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法看得到代表bean文件的资源定义以后的载入过程。
[java] view plaincopy
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { ....... try { <span style="color:#33ff33;">//这里通过Resource得到InputStream的IO流</span> InputStream inputStream = encodedResource.getResource().getInputStream(); try { <span style="color:#33ff33;"> //从InputStream中得到XML的解析源</span> InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } <span style="color:#33ff33;">//这里是具体的解析和注册过程</span> return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { <span style="BACKGROUND-COLOR: #33ff33">//关闭从Resource中得到的IO流</span> inputStream.close(); } } ......... } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); <span style="color:#33ff33;">//通过解析得到DOM,然后完成bean在IOC容器中的注册</span> Document doc = this.documentLoader.loadDocument( inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware); return registerBeanDefinitions(doc, resource); } ....... }
在doLoadBeanDefinitions(…)先把定义文件解析为DOM对象,然后进行具体的注册过程。
[java] view plaincopy
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { <span style="color:#33ff33;">//具体的注册过程,首先得到XmlBeanDefinitionDocumentReader来处理xml的bean定义文件</span> BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(this.getEnvironment()); int countBefore = getRegistry().getBeanDefinitionCount(); <span style="color:#33ff33;">//调用注册方法</span> documentReader.registerBeanDefinitions(doc,createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } <p> </p>
具体的过程在BeanDefinitionDocumentReader中完成,在DefaultBeanDefinitionDocumentReader的方法中完成bean定义文件的解析和IOC容器中bean的初始化。
[java] view plaincopy
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
[java] view plaincopy
protected void doRegisterBeanDefinitions(Element root) { <span style="color:#33ff33;">……(注:省略号表示省略掉了代码) //通过代理delegate解析</span> BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createHelper(readerContext, root, parent); preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
[java] view plaincopy
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { <span style="color:#33ff33;">//得到xml文件的子节点,比如各个bean节点</span> NodeList nl = root.getChildNodes(); <span style="color:#33ff33;">//对每个节点进行分析处理</span> 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)) { <span style="color:#33ff33;">//这里是解析过程的调用,对缺省的元素进行分析比如bean元素</span> parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
[java] view plaincopy
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { <span style="color:#33ff33;">//对元素Import进行处理</span> if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } <span style="color:#33ff33;">//对我们熟悉的bean元素进行处理</span> else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { <span style="color:#33ff33;">// recurse</span> doRegisterBeanDefinitions(ele); } }
[java] view plaincopy
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { <span style="color:#33ff33;">//委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包括了具体的bean解析过程。把解析bean文件得到的信息放在BeanDefinition里,它是bean信息的主要载体,也是IOC容器的管理对象。</span> BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { <span style="color:#33ff33;">// Register the final decorated instance. //向IOC容器注册,实际是放到IOC容器的一个map里</span>
[java] view plaincopy
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { …… } <span style="color:#33ff33;">// Send registration event. //这里向IOC容器发送事件,表示解析和注册完成</span> getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); }
可以看到在processBeanDefinition中对具体bean元素的解析是交给BeanDefinitionParserDelegate来完成的。我们接着看其实现的函数:
[java] view plaincopy
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { <span style="color:#33ff33;">……(省略)</span> AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { <span style="color:#33ff33;">//BeanDefinition解析过程</span> ……(省略) String[] aliasesArray = StringUtils.toStringArray(aliases); <span style="color:#33ff33;">//将解析完的bean定义包装后返回</span> return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; } <p> </p>
在这里对定义文件中的bean元素进行解析,得到AbstractBeanDefinition,并用BeanDefinitionHolder封装后返回。
下面我们看解析完的bean如何在IOC容器中注册:在BeanDefinitionReaderUtils中调用的是:
[java] view plaincopy
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { <span style="color:#33ff33;">// Register bean definition under primary name. //得到需要注册bean的名字</span> String beanName = definitionHolder.getBeanName(); <span style="color:#33ff33;">//调用IOC来注册bean的过程,需要得到BeanDefinition</span> registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); <span style="color:#33ff33;">// Register aliases for bean name, if any. //将别名通过IOC容器和bean联系起来进行注册</span> String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } }
接着我们看看bean的注册实现,从上面看到其调用的是BeanDefinitionRegistry的方法registerBeanDefinition完成注册,跟踪代码可知BeanFactory容器的一个实现DefaultListableBeanFactory实现了这个接口并提供了注册的具体实现:
[java] view plaincopy
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException { ...... if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span> …… } } synchronized (this.beanDefinitionMap) { Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span> …… } else { if (this.logger.isInfoEnabled()) { …… } } } else { this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } this.beanDefinitionMap.put(beanName, beanDefinition); resetBeanDefinition(beanName); } }
可以看到整个注册过程很简单,就是将bean添加到BeanDefinition的map中。这样就完成了bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。