4 BeanFactory容器的设计原理

BeanFactory接口提供了使用IoC容器的规范。 在这个基础上,Spring 还提供了符合这个IoC容器接口的一系列容器的实现供开发人员使用。我们以XmlBeanFactory的实现为例来说明简单IoC容器的设计原理。如图所示为XmlBeanFactory设计的类继承关系。

这里写图片描述

可以看到,作为一个简单loC容器系列最底层实现的XmlBeanFactory,与我们在Spring应用中用到的那些上下文相比,有一个非常明显的特点:它只提供最基本的IoC容器的功能。理解这一点有助于我们理解ApplicationContext与基本的BeanFactory之间的区别和联系。我们可以认为直接的BeanFactory实现是IoC容器的基本形式,而各种ApplicationContext的实现是IoC容器的高级表现形式。关于ApplicationContext的分析,以及它与BeanFactory相比的增强特性都会在下面进行详细的分析。
让我们好好地看一下图中的继承关系,从中可以清楚地看到类之间的联系,它们都是IoC容器系列的组成部分。在设计这个容器系列时,我们可以从继承体系的发展上看到IoC容器各项功能的实现过程。如果要扩展自己的容器产品,建议读者最好在继承体系中检查一下,看看Spring是不是已经提供了现成的或相近的容器实现供我们参考。下面就从我们比较熟悉的XmlBeanFactory的实现人手进行分析,来看看一个基本的IoC容器是怎样实现的。
仔细阅读XmlBeanFactory的源码,在一开始的注释里会看到对XmlBeanFactory功能的简要说明,从代码的注释还可以看到,这是RodJohnson在2001年就写下的代码,可见这个类应该是Spring的元老类了。XmlBeanFactory继承自DefaultListableBeanFactory这个类,后者非常重要,是我们经常要用到的一个IoC容器的实现,比如在设计应用上下文ApplicationContext时就会用到它。我们会看到这个DefaultListableBeanFactory实际上包含了基本IoC容器所具有的重要功能,也是在很多地方都会用到的容器系列中的一个基本产品。
在Spring中,实际上是把DefaultListableBeanFactory作为一个默认的功能完整的IoC容器来使用的。XmlBeanFactory在继承了DefaultListableBeanFactory容器的功能的同时,增加了新的功能,这些功能很容易从XmlBeanFactory的名字上猜到。它是一个与XML相关的
BeanFactory,也就是说它是一个可以读取以XML文件方式定义的BeanDefinition的IoC容器。这些实现XML读取的功能是怎样实现的呢?对这些XML文件定义信息的处理并不是由
XmlBeanFactory直接完成的。在XmlBeanFactory中,初始化了一个
XmlBeanDefinitionReader对象,有了这个Reader对象,那些以XML方式定义的BeanDefinition就有了处理的地方。我们可以看到,对这些XML形式的信息的处理实际上是由这个XmlBeanDefinitionReader来完成的。
构造XmlBeanFactory这个loC容器时,需要指定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类来给出。Resource是Spring用来封装1/0操作的类。比如,我们的BeanDefinition信息是以XML文件形式存在的,那么可以使用像”ClassPath-Resourceres=newClassPathResource(“beans.xml”);”这样具体的ClassPathResource来构造需要的Resource,然后将Resource作为构造参数传递给XmlBeanFactory构造函数。这样,IoC容器就可以方便地定位到需要的BeanDefinition信息来对Bean完成容器的初始化和依赖注入过程。
XmlBeanFactory的功能是建立在DefaultListableBeanFactory这个基本容器的基础上的,并在这个基本容器的基础上实现了其他诸如XML读取的附加功能。对于这些功能的实现原理,看一看XmlBeanFactory的代码实现就能很容易地理解。如代码清单所示,在XmlBeanFactory构造方法中需要得到Resource对象。对XmlBeanDefinitionReader对象的初始化,以及使用这个对象来完成对loadBeanDefinitions的调用,就是这个调用启动从Resource中载入BeanDefinitions的过程,LoadBeanDefinitions同时也是IoC容器初始化的重要组成部分。

public class XmlBeanFactory extends DefaultListableBeanFactory {

    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

    /**
     * Create a new XmlBeanFactory with the given resource,
     * which must be parsable using DOM.
     * @param resource XML resource to load bean definitions from
     * @throws BeansException in case of loading or parsing errors
     */
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }

    /**
     * Create a new XmlBeanFactory with the given input stream,
     * which must be parsable using DOM.
     * @param resource XML resource to load bean definitions from
     * @param parentBeanFactory parent bean factory
     * @throws BeansException in case of loading or parsing errors
     */
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }
}

我们看到XmlBeanFactory使用了DefaultListableBeanFactory作为基类,DefaultListable-BeanFactory是很重要的一个IoC实现,在其他IoC容器中,比如ApplicationContext,其实现的基本原理和XmJBeanFactory一样,也是通过持有或者扩展DefaultListableBeanFactory来获得基本的IoC容器的功能的。细心的读者可以发现在spring5中XmlBeanFactory已被废弃,建议使用DefaultListableBeanFactory和XmlBeanDefinitionReader来自己实现XmlBeanFactory。

For advanced needs, consider using a {@link DefaultListableBeanFactory} with
an {@link XmlBeanDefinitionReader}. The latter allows for reading from multiple XML
resources and is highly configurable in its actual XML parsing behavior.

参考XmlBeanFactory的实现,我们以编程的方式使用DefaultListableBeanFactory。从中我们可以着到IoC容器使用的一些基本过程。因为这个编程式使用容器的过程,很清楚揭示了在IoC容器实现中的那些关键的类(比如Resource、OefaultListableBeanFactory和BeanDefinitionReader)之间的相互关系,例如它们是如何把IoC容器的功能解耦的,又是如何结合在一起为IoC容器服务的,等等。在如下代码清单中可以看到编程式使用IoC容器的过程。

        ClassPathResource res = new ClassPathResource("beans.xml");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(res);

这样,我们就可以通过factory对象来使用DefaultListableBeanFactory这个IoC容器了。在使用loC容器时,需要如下几个步骤:
1. 创建IoC配置文件的抽象资源,这个抽象资源包含了BeanDefinition的定义信息。
2. 创建一个BeanFactory,这里使用DefaultListableBeanFactory。
3. 创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition,通过一个回调配置给BeanFactory。
4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成。完成整个载人和注册Bean定义之后,需要的IoC容器就建立起来了。这个时候就可以直接使用IoC容器了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值