Spring IoC容器-BeanFactory

IoC的职责

上一篇博文介绍了IoC的概念,从实际应用角度看,IoC这种编程思想主要解决的问题有两个:

对象创建管理:使用IoC时,应用这无需关心所依赖对象如何创建如何获取,IoC将这部分思想逻辑从客户端玻剥离出来,实现对客户端逻辑的低入侵。

对象依赖关系管理:这是IoC的核心功能,IoC通过对象创建管理,以及通过识别各个对象之间的依赖关系,将这些对象所依赖的对象注入、绑定。

Spring IoC容器

Spring IoC容器是实现“控制反转”编程思想的一个框架,Spring IoC容器除了能够解决上述IoC的两个主要问题之外,还提供了线程管理、服务集成、查找服务等诸多功能。更利于使用,Spring IoC容器有两种,BeanFactory和ApplicationContext。本文主要介绍BeanFactory。

什么是BeanFactory

首先看一张图片:

再看看BeanFacotry的源代码

public interface BeanFactory {
	//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
	//如果需要得到工厂本身,需要转义
	String FACTORY_BEAN_PREFIX = "&";

	//根据bean的名字,获取在IOC容器中得到bean实例
	Object getBean(String name) throws BeansException;

	//根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	<T> T getBean(Class<T> requiredType) throws BeansException;

	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	//提供对bean的检索,看看是否在IOC容器有这个名字的bean
	boolean containsBean(String name);

	//根据bean名字得到bean实例,并同时判断这个bean是不是单例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	//得到bean实例的Class类型
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
	String[] getAliases(String name);
}

BeanFactory并不是一种实现方式,而是一个规范。因为在Spring中,BeanFactory是一个接口,是Spring中工厂的顶层规范,这个规范中给出了管理Bean的通用方法的定义,例如:getBean(),containsBean()等。BeanFactory定义了方法,提供了规范,真正的IoC的实现是通过实现BeanFactory接口完成的。比如:

ClassPathXmlApplicationContext, 
DefaultListableBeanFactory, 
FileSystemXmlApplicationContext等等。

BeanFactory的实现机制

public static void main(String[] args)
{
    DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
    BeanFactory container = (BeanFactory)bindViaCode(beanRegistry);
    FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
    newsProvider.getAndPersistNews();
}
public static BeanFactory bindViaCode(BeanDefinitionRegistry registry)
{
    AbstractBeanDefinition newsProvider = new RootBeanDefinition(FXNewsProvider.class,true);
    AbstractBeanDefinition newsListener = new RootBeanDefinition(DowJonesNewsListener.class,true);
    AbstractBeanDefinition newsPersister = new RootBeanDefinition(DowJonesNewsPersister.class,true);
    // 将bean定义注册到容器中
    registry.registerBeanDefinition("djNewsProvider", newsProvider);
    registry.registerBeanDefinition("djListener", newsListener);
    registry.registerBeanDefinition("djPersister", newsPersister);
    // 指定依赖关系
    // 1. 可以通过构造方法注入方式
    ConstructorArgumentValues argValues = new ConstructorArgumentValues();
    argValues.addIndexedArgumentValue(0, newsListener);
    argValues.addIndexedArgumentValue(1, newsPersister);
    newsProvider.setConstructorArgumentValues(argValues);
    // 2. 或者通过setter方法注入方式
    MutablePropertyValues propertyValues = new MutablePropertyValues();
    propertyValues.addPropertyValue(new ropertyValue("newsListener",newsListener));
    propertyValues.addPropertyValue(new PropertyValue("newPersistener",newsPersister));
    newsProvider.setPropertyValues(propertyValues);
    // 绑定完成 2
    return (BeanFactory)registry;
}	

DefaultListableBeanFactory是一个比较常见的BeanFactory的实现类。DefaultListableBeanFactory除了间接实现了BeanFactory接口,还实现了BeanDefinitionRegistry接口,这个接口才是真正的Bean的注册管理的接口。从上面BeanFactory接口的定义源码可以看出来,BeanFactory接口只定义如何访问Spring IoC容器内Bean的方法,Bean的具体管理方法由BeanFactory的具体实现类完成。BeanDefinitionRegistry接口定义了Bean的注册逻辑。通常BeanFactroy的实现类都需要实现这个接口来管理Bean的注册。它们之间的关系如下图:

    打个比方说,BeanDefinitionRegistry就像图书馆的书架,所有的书是放在书架上的。虽然还书或者借书都是跟图书馆(也就是BeanFactory)打交道,但书架才是图书馆存放各类图书的地方。所以,书架相对于图书馆来说,就是它的“BeanDefinitionRegistry”。 每一个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之相对应,该BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性等。当客户端向BeanFactory请求相应对象的时候,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。RootBeanDefinitionChildBean-DefinitionBeanDefinition的两个主要实现类。

    在main方法中,首先构造一个DefaultListableBeanFactory 作为BeanDefinition-Registry,然后将其交给bindViaCode方法进行具体的对象注册和相关依赖管理,然后通过bindViaCode返回的BeanFactory取得需要的对象,最后执行相应逻辑。在我们的实例里,当然就是取得FXNewsProvider进行新闻的处理。

    在bindViaCode方法中,首先针对相应的业务对象构造与其相对应的BeanDefinition,使用了RootBeanDefinition 作为BeanDefinition 的实现类。构造完成后, 将这些BeanDefinition注册到通过方法参数传进来的BeanDefinitionRegistry中。之后,因为我们的FXNewsProvider是采用的构造方法注入,所以,需要通过ConstructorArgument-Values为其注入相关依赖。

    参考资料《Spring揭秘》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值