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

  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中。

  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中。

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

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

  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中定义了载入过程

  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文件的资源定义以后的载入过程。

  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. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
  23. throws BeanDefinitionStoreException {
  24. try {
  25. int validationMode = getValidationModeForResource(resource);
  26. <span style="color:#33ff33;">//通过解析得到DOM,然后完成bean在IOC容器中的注册</span>
  27. Document doc = this.documentLoader.loadDocument(
  28. inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);
  29. return registerBeanDefinitions(doc, resource);
  30. }
  31. .......
  32. }

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

  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的初始化。

  1. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  2. this.readerContext = readerContext;
  3. logger.debug("Loading bean definitions");
  4. Element root = doc.getDocumentElement();
  5. doRegisterBeanDefinitions(root);
  6. }
  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. preProcessXml(root);
  7. parseBeanDefinitions(root, this.delegate);
  8. postProcessXml(root);
  9. this.delegate = parent;
  10. }
  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. }
  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. }
  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>
  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来完成的。我们接着看其实现的函数:

  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中调用的是:

  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. <span style="color:#33ff33;">// Register aliases for bean name, if any.
  9. //将别名通过IOC容器和bean联系起来进行注册</span>
  10. String[] aliases = definitionHolder.getAliases();
  11. if (aliases != null) {
  12. for (String aliase : aliases) {
  13. registry.registerAlias(beanName, aliase);
  14. }
  15. }
  16. }

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

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

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

spring IOC源码分析(2)的更多相关文章

  1. Spring IOC 源码分析

    Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...

  2. spring IoC源码分析 (3)Resource解析

    引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource  ...

  3. Spring IoC 源码分析 (基于注解) 之 包扫描

    在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...

  4. Spring Ioc源码分析系列--Ioc的基础知识准备

    Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...

  5. Spring Ioc源码分析系列--前言

    Spring Ioc源码分析系列--前言 为什么要写这个系列文章 首先这是我个人很久之前的一个计划,拖了很久没有实施,现在算是填坑了.其次,作为一个Java开发者,Spring是绕不开的课题.在Spr ...

  6. Spring Ioc源码分析系列--Ioc源码入口分析

    Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...

  7. Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析

    Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...

  8. Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理

    Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...

  9. Spring Ioc源码分析系列--Bean实例化过程(一)

    Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...

  10. Spring Ioc源码分析系列--Bean实例化过程(二)

    Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...

随机推荐

  1. Android打包程序

    右击项目->导出export next,完成相关信息填写将得到.apk文件,即可部署到手机上. 第一次: 然后打开目录就可以看到生成的apk,可以发布到各大市场上.

  2. c++中静态成员变量 静态成员函数 全局变量与静态函数的关系 字符串中括号的匹配编程 (笔试经历)

    笔试经历 1 类中的静态变量不能通过构造函数参数列表来初始化,因为静态变量不属于哪个对象.同时静态变量在不初始化的情况下系统会自动为变量赋值,数值型赋值为零,字符型赋值为空. 非静态变量只有在定义时才 ...

  3. Xcode文件目录选中变成白色, 解决方案

    新版Xcode很不稳定, 有时候被选中文件变成白色, 看着很不舒服, 以前都是毫无办法, 等它自动变回来, 现在有一个解决办法, 点击文件目录上面的选项, 随便切换一个再切换回来, 发现文件目录颜色回 ...

  4. C语言内存管理

    作用域: 1.代码块儿作用域: 注意的是:这里面{}就代表一个代码块儿,里面的东西是独立的,不可被其他地方访问的. 2.函数作用域 3.文件作用域 先提一下 在当前有一个文件,main.c 还有一个文 ...

  5. Linux上安装Squall

    Squall是Storm之上的类SQL查询工具,能够将类SQL语句转换成topology,然后提交给Storm运行. 安装Squall前要先安装Java和sbt(simple build tool), ...

  6. mapping 详解4(mapping setting)

    mapping type 映射设置一般发生在: 1. 增加新的 index 的时候,添加 mapping type,对 fields 的映射进行设置 PUT twitter { "mappi ...

  7. Android开发学习

    Android Studio中文社区:http://www.android-studio.org/ Android Studio官方网站地址:http://developer.android.com/ ...

  8. 在centos中php 在连接mysql的时候,出现Can't connect to MySQL server on 'XXX' (13)

    原文连接:http://hi.baidu.com/zwfec/item/64ef5ed9bf1cb3feca0c397c 红色的是命令 SQLSTATE[HY000] [2003] Can't con ...

  9. 编程中的 if ()else() 语句

    例句    if()  else() double d = Convert.ToDouble(Console .ReadLine()); if (d >= 60 && d< ...

  10. [01] Oracle数据库简介

    Oracle关系型数据库:建立在关系模型上. Oracle10g:g(grid)网格技术,网格计算(Grid Computing)通过网络共享,将大量的计算机连接起来,联合各个计算机的多余处理能力,产 ...