美文网首页程序员
spring源码学习 - xml方式bean的解析注册过程

spring源码学习 - xml方式bean的解析注册过程

作者: ouyangan | 来源:发表于2017-01-02 04:30 被阅读569次
    为什么开始看spring的源码
    • 半路转行写代码快一年半了,从开始工作就在使用spring框架,虽然会用,会搭框架,但是很多时候不懂背后的原理,比如:spring是怎样控制事务的,springmvc是怎样处理请求的,aop是如何实现的...这让人感觉非常不踏实,那就开始慢慢边看书边研究spring的源码吧!!!
    怎样高效的看源码
    • 我的答案是带着具体的问题去看源码,不然非常容易陷入源码细节中不能自拔,然后就晕了,最后你发现这看了半天看的是啥玩意啊.
    spring容器核心类结构图,方便我们理清思路,主要参考自书籍<<spring源码深度解析 >>
    spring容器核心类结构图
    下面正式开始源码bug
    1. 创建一个简单的javaBean. 下面debug过程尽量只针对该bean的初始化过程进行跟踪,以免陷入源码细节出不来...
    public class TestBean {
      private String name;
    
      public TestBean() {
      }
    
      public TestBean(String name) {
          this.name = name;
      }
    
      public String getName() {
          return name;
      }
    
      public void setName(String name) {
          this.name = name;
      }
    }
    
    1. spring.xml定义
        <bean id="testBean" class="com.hunt.debug.TestBean">
            <property name="name" value="spring"/>
        </bean>
    
    1. 利用spring集成单元测试
    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration(value = "classpath:src/main/webapp")
    @ContextConfiguration({"classpath:spring.xml", "classpath:spring/spring-mvc.xml"})
    @Transactional
    public class DebugSpring {
        private static final Logger log = LoggerFactory.getLogger(DebugSpring.class);
        @Test
        public void testLoad() throws IOException {
            Resource resource = new ClassPathResource("spring.xml");
            BeanFactory xmlBeanFactory = new XmlBeanFactory(resource);
            TestBean testBean = xmlBeanFactory.getBean("testBean", TestBean.class);
            log.debug("test bean name is :{}", testBean.getName());
        }
    }
    
    1. 开始debug

    2. 这里内部真正调用的是第二个构造器


      XmlBeanFactory类结构图
    3. 初始化入口:this.reader.loadBeanDefinitions(resource);

    4. 实际上是private final XmlBeanDefinitionReader reader这个对象负责spring容器的初始化,包括:xml配置文件载入,验证,解析,bean的注册

      XmlBeanDefinitionReader类结构图
    5. 继续进入loadBeanDefinitions(Resource resource)

    6. 进入到的是XmlBeanDefinitionReader中的loadBeanDefinitions(EncodedResource encodedResource):

      Paste_Image.png
    7. 继续进入XmlBeanDefinitionReader中的doLoadBeanDefinitions(InputSource inputSource, Resource resource)`:

      Paste_Image.png
    8. 继续进入XmlBeanDefinitionReader中的registerBeanDefinitions(Document doc, Resource resource):

      Paste_Image.png
    9. 准备数据,进入registerBeanDefinitions(Document doc, XmlReaderContext readerContext):

      Paste_Image.png
    10. 开始进入解析流程doRegisterBeanDefinitions(Element root):

      Paste_Image.png
    11. 终于做好了所有的准备,按照命名空间类别进行解析,解析规则是如果是<beans></beans>则按照默认方式否则按照自定义解析方式...跟进parseBeanDefinitions(root, this.delegate);:

      Paste_Image.png
      Paste_Image.png
    12. 按照标签规则进行解析


      Paste_Image.png
    13. 组装BeanDefinitionHolder并在容器中进行注册 ,为什么需要对容器对象进行包装呢,因为容器对容器和别名是分两个属性进行维护的.

      Paste_Image.png
    14. 组装BeanDefinitionHolder过程

    15. 创建容器数据对象过程,设置数据对象的属性


      Paste_Image.png
    16. 来看下容器对象中的数据对象到底是什么样子的:


    17. 回到processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate),继续最后一步: 向容器中进行注册!!!

      Paste_Image.png
    18. 最后一步,向容器注册是在DefaultListableBeanFactory中的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)进行实现的


    19. 到这里完成了bean向容器的注册,我们可以看下beanDefinitionMap容器已经有了testBean,到这里我们定义的testBean整个初始化过程就结束了

      Paste_Image.png
    参考资料

    相关文章

      网友评论

        本文标题:spring源码学习 - xml方式bean的解析注册过程

        本文链接:https://www.haomeiwen.com/subject/zntivttx.html