zoukankan      html  css  js  c++  java
  • spring IOC源码分析(2)

    refresh这个方法包含了整个BeanFactory初始化的过程,定位资源由obtainFreshBeanFactory()来完成,

    [java] view plaincopy
     
    1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
    2.         refreshBeanFactory();  
    3.         ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
    4.         if (logger.isDebugEnabled()) {  
    5.             logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
    6.         }  
    7.         return beanFactory;  
    8.     }  

             可以看到其调用了refreshBeanFactory(),refreshBeanFactory()在这个类中是抽象方法,其实现在AbstractRefreshableApplicationContext中。

    [java] view plaincopy
     
    1. protected final void refreshBeanFactory() throws BeansException {  
    2.         if (hasBeanFactory()) {  
    3.             destroyBeans();  
    4.             closeBeanFactory();  
    5.         }  
    6.         try {  
    7.             DefaultListableBeanFactory beanFactory = createBeanFactory();  
    8.             beanFactory.setSerializationId(getId());  
    9.             customizeBeanFactory(beanFactory);  
    10.             loadBeanDefinitions(beanFactory);  
    11.             synchronized (this.beanFactoryMonitor) {  
    12.                 this.beanFactory = beanFactory;  
    13.             }  
    14.         }  
    15.         catch (IOException ex) {  
    16.             ……  
    17.         }  
    18. }  

              在这个方法中,先判断BeanFactory是否存在,如果存在则先销毁beans并关闭beanFactory,接着创建DefaultListableBeanFactory,并调用loadBeanDefinitions(beanFactory)装载bean定义。loadBeanDefinitions方法同样是抽象方法,是由其子类实现的,也即在AbstractXmlApplicationContext中。

    [java] view plaincopy
     
    1. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {    
    2.    <span style="color:#33ff33;"> // 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件</span>    
    3.     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);    
    4.     
    5.     <span style="color:#33ff33;">//这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的</span>    
    6.  <span style="color:#33ff33;">   //因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader </span>   
    7.     beanDefinitionReader.setResourceLoader(this);    
    8.     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));    
    9.     
    10.     initBeanDefinitionReader(beanDefinitionReader);    
    11.     <span style="color:#33ff33;">//这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理</span>    
    12.     loadBeanDefinitions(beanDefinitionReader);    
    13. }    

              接着我们转到beanDefinitionReader中进行处理

    [java] view plaincopy
     
    1. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {    
    2.     Resource[] configResources = getConfigResources();    
    3.     if (configResources != null) {    
    4.       <span style="color:#33ff33;">  //调用XmlBeanDefinitionReader来载入bean定义信息。</span>    
    5.         reader.loadBeanDefinitions(configResources);    
    6.     }    
    7.     String[] configLocations = getConfigLocations();    
    8.     if (configLocations != null) {    
    9.         reader.loadBeanDefinitions(configLocations);    
    10.     }    
    11. }    

             可以到org.springframework.beans.factory.support看一下BeanDefinitionReader的结构

            在其抽象父类AbstractBeanDefinitionReader中定义了载入过程

    [java] view plaincopy
     
    1. public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {    
    2.    <span style="color:#33ff33;"> //这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader </span>   
    3.     ResourceLoader resourceLoader = getResourceLoader();    
    4.     <span style="color:#33ff33;">//如果没有找到我们需要的ResourceLoader,直接抛出异常</span>    
    5.     if (resourceLoader instanceof ResourcePatternResolver) {    
    6.         <span style="color:#33ff33;">// 这里处理我们在定义位置时使用的各种pattern,需要 ResourcePatternResolver来完成</span>    
    7.         try {    
    8.             Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);    
    9.             int loadCount = loadBeanDefinitions(resources);    
    10.             return loadCount;    
    11.         }    
    12.         ........    
    13.     }    
    14.     else {    
    15.         <span style="color:#33ff33;">// 这里通过ResourceLoader来完成位置定位</span>    
    16.         Resource resource = resourceLoader.getResource(location);    
    17.             <span style="color:#33ff33;"> // 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader来使用了</span>    
    18.         int loadCount = loadBeanDefinitions(resource);    
    19.         return loadCount;    
    20.     }    
    21. }   



     


            看到第8、16行,结合上面的ResourceLoader与ApplicationContext的继承关系图,可以知道此时调用的是DefaultResourceLoader中的getSource()方法定位Resource,因为ClassPathXmlApplicationContext本身就是DefaultResourceLoader的实现类,所以此时又回到了ClassPathXmlApplicationContext中来。

            继续回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法看得到代表bean文件的资源定义以后的载入过程。

    [java] view plaincopy
     
    1. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    
    2.     .......    
    3.     try {    
    4.         <span style="color:#33ff33;">//这里通过Resource得到InputStream的IO流</span>    
    5.         InputStream inputStream = encodedResource.getResource().getInputStream();    
    6.         try {    
    7.            <span style="color:#33ff33;"> //从InputStream中得到XML的解析源</span>    
    8.             InputSource inputSource = new InputSource(inputStream);    
    9.             if (encodedResource.getEncoding() != null) {    
    10.                 inputSource.setEncoding(encodedResource.getEncoding());    
    11.             }    
    12.             <span style="color:#33ff33;">//这里是具体的解析和注册过程</span>    
    13.             return doLoadBeanDefinitions(inputSource, encodedResource.getResource());    
    14.         }    
    15.         finally {    
    16.             <span style="BACKGROUND-COLOR: #33ff33">//关闭从Resource中得到的IO流</span>    
    17.             inputStream.close();    
    18.         }    
    19.     }    
    20.        .........    
    21. }    
    22.     
    23. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)    
    24.         throws BeanDefinitionStoreException {    
    25.     try {    
    26.         int validationMode = getValidationModeForResource(resource);    
    27.         <span style="color:#33ff33;">//通过解析得到DOM,然后完成bean在IOC容器中的注册</span>    
    28.         Document doc = this.documentLoader.loadDocument(    
    29.                 inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);    
    30.         return registerBeanDefinitions(doc, resource);    
    31.     }    
    32. .......    
    33. }  

            在doLoadBeanDefinitions(…)先把定义文件解析为DOM对象,然后进行具体的注册过程。

    [java] view plaincopy
     
    1. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {  
    2.         <span style="color:#33ff33;">//具体的注册过程,首先得到XmlBeanDefinitionDocumentReader来处理xml的bean定义文件</span>  
    3.         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  
    4.         documentReader.setEnvironment(this.getEnvironment());  
    5.         int countBefore = getRegistry().getBeanDefinitionCount();  
    6.         <span style="color:#33ff33;">//调用注册方法</span>  
    7.                      documentReader.registerBeanDefinitions(doc,createReaderContext(resource));  
    8.              return getRegistry().getBeanDefinitionCount() - countBefore;  
    9. }  
    10. <p> </p>  

            具体的过程在BeanDefinitionDocumentReader中完成,在DefaultBeanDefinitionDocumentReader的方法中完成bean定义文件的解析和IOC容器中bean的初始化。

    [java] view plaincopy
     
    1. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
    2.         this.readerContext = readerContext;  
    3.   
    4.         logger.debug("Loading bean definitions");  
    5.         Element root = doc.getDocumentElement();  
    6.   
    7.         doRegisterBeanDefinitions(root);  
    8. }  
    [java] view plaincopy
     
    1. protected void doRegisterBeanDefinitions(Element root) {  
    2.         <span style="color:#33ff33;">……(注:省略号表示省略掉了代码)  
    3.         //通过代理delegate解析</span>  
    4.         BeanDefinitionParserDelegate parent = this.delegate;  
    5.         this.delegate = createHelper(readerContext, root, parent);  
    6.   
    7.         preProcessXml(root);  
    8.         parseBeanDefinitions(root, this.delegate);  
    9.         postProcessXml(root);  
    10.   
    11.         this.delegate = parent;  
    12. }  
    [java] view plaincopy
     
    1. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  
    2.         if (delegate.isDefaultNamespace(root)) {  
    3.             <span style="color:#33ff33;">//得到xml文件的子节点,比如各个bean节点</span>  
    4.             NodeList nl = root.getChildNodes();  
    5.             <span style="color:#33ff33;">//对每个节点进行分析处理</span>  
    6.             for (int i = 0; i < nl.getLength(); i++) {  
    7.                 Node node = nl.item(i);  
    8.                 if (node instanceof Element) {  
    9.                     Element ele = (Element) node;  
    10.                     if (delegate.isDefaultNamespace(ele)) {  
    11.                         <span style="color:#33ff33;">//这里是解析过程的调用,对缺省的元素进行分析比如bean元素</span>  
    12.                         parseDefaultElement(ele, delegate);  
    13.                     }  
    14.                     else {  
    15.                         delegate.parseCustomElement(ele);  
    16.                     }  
    17.                 }  
    18.             }  
    19.         }  
    20.         else {  
    21.             delegate.parseCustomElement(root);  
    22.         }  
    23. }  
    [java] view plaincopy
     
    1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
    2.         <span style="color:#33ff33;">//对元素Import进行处理</span>  
    3.         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
    4.             importBeanDefinitionResource(ele);  
    5.         }  
    6.         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
    7.             processAliasRegistration(ele);  
    8.         }  
    9.         <span style="color:#33ff33;">//对我们熟悉的bean元素进行处理</span>  
    10.         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
    11.             processBeanDefinition(ele, delegate);  
    12.         }  
    13.         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  
    14.             <span style="color:#33ff33;">// recurse</span>  
    15.             doRegisterBeanDefinitions(ele);  
    16.         }  
    17. }  
    [java] view plaincopy
     
    1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
    2.         <span style="color:#33ff33;">//委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包括了具体的bean解析过程。把解析bean文件得到的信息放在BeanDefinition里,它是bean信息的主要载体,也是IOC容器的管理对象。</span>  
    3.         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  
    4.         if (bdHolder != null) {  
    5.              bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
    6.             try {  
    7.                 <span style="color:#33ff33;">// Register the final decorated instance.  
    8.                                //向IOC容器注册,实际是放到IOC容器的一个map里</span>         
    [java] view plaincopy
     
    1.                                   BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
    2.     }  
    3.     catch (BeanDefinitionStoreException ex) {  
    4.         ……  
    5.     }  
    6.     <span style="color:#33ff33;">// Send registration event.  
    7.     //这里向IOC容器发送事件,表示解析和注册完成</span>  
    8.                     getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  
    9. }  

             可以看到在processBeanDefinition中对具体bean元素的解析是交给BeanDefinitionParserDelegate来完成的。我们接着看其实现的函数:

    [java] view plaincopy
     
    1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
    2.         <span style="color:#33ff33;">……(省略)</span>  
    3.         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
    4.         if (beanDefinition != null) {  
    5.             <span style="color:#33ff33;">//BeanDefinition解析过程</span>  
    6.                                 ……(省略)  
    7.             String[] aliasesArray = StringUtils.toStringArray(aliases);  
    8.                            <span style="color:#33ff33;">//将解析完的bean定义包装后返回</span>  
    9.             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
    10.         }  
    11.         return null;  
    12. }  
    13. <p> </p>  


             在这里对定义文件中的bean元素进行解析,得到AbstractBeanDefinition,并用BeanDefinitionHolder封装后返回。

            下面我们看解析完的bean如何在IOC容器中注册:在BeanDefinitionReaderUtils中调用的是:

    [java] view plaincopy
     
    1. public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  
    2. throws BeanDefinitionStoreException {  
    3.         <span style="color:#33ff33;">// Register bean definition under primary name.  
    4.         //得到需要注册bean的名字</span>  
    5.         String beanName = definitionHolder.getBeanName();  
    6.         <span style="color:#33ff33;">//调用IOC来注册bean的过程,需要得到BeanDefinition</span>  
    7.         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  
    8.   
    9.         <span style="color:#33ff33;">// Register aliases for bean name, if any.  
    10.         //将别名通过IOC容器和bean联系起来进行注册</span>  
    11.         String[] aliases = definitionHolder.getAliases();  
    12.         if (aliases != null) {  
    13.             for (String aliase : aliases) {  
    14.                 registry.registerAlias(beanName, aliase);  
    15.             }  
    16.         }  
    17. }  


             接着我们看看bean的注册实现,从上面看到其调用的是BeanDefinitionRegistry的方法registerBeanDefinition完成注册,跟踪代码可知BeanFactory容器的一个实现DefaultListableBeanFactory实现了这个接口并提供了注册的具体实现:

    [java] view plaincopy
     
    1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {  
    2.   
    3.         ......  
    4.         if (beanDefinition instanceof AbstractBeanDefinition) {  
    5.             try {  
    6.                 ((AbstractBeanDefinition) beanDefinition).validate();  
    7.             }  
    8.             catch (BeanDefinitionValidationException ex) {  
    9.                 <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>  
    10.                 ……  
    11.             }  
    12.         }  
    13.   
    14.         synchronized (this.beanDefinitionMap) {  
    15.             Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
    16.             if (oldBeanDefinition != null) {  
    17.                 if (!this.allowBeanDefinitionOverriding) {  
    18.                     <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>  
    19.                     ……  
    20.                 }  
    21.                 else {  
    22.                     if (this.logger.isInfoEnabled()) {  
    23.                         ……  
    24.                     }  
    25.                 }  
    26.             }  
    27.             else {  
    28.                 this.beanDefinitionNames.add(beanName);  
    29.                 this.frozenBeanDefinitionNames = null;  
    30.             }  
    31.             this.beanDefinitionMap.put(beanName, beanDefinition);  
    32.   
    33.             resetBeanDefinition(beanName);  
    34.         }  
    35. }  

             可以看到整个注册过程很简单,就是将bean添加到BeanDefinition的map中。这样就完成了bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。

  • 相关阅读:
    费曼学习法
    Ubuntu修改系统默认编码
    如何在Ubuntu 18.04上安装和使用PostgreSQL
    Bash简介 & Bash是如何处理命令的
    ubuntu环境变量的三种设置方法
    psql 工具详细使用介绍
    使用ubuntu server18.04 搭建odoo12运行环境
    Ubuntu修改时区和更新时间
    Ubuntu18.04修改apt-get源
    对表内数据间隔特定的长度求和
  • 原文地址:https://www.cnblogs.com/downey/p/4888329.html
Copyright © 2011-2022 走看看