当前位置: 代码迷 >> 综合 >> Spring IoC容器-BeanFactory
  详细解决方案

Spring IoC容器-BeanFactory

热度:1   发布时间:2024-02-12 05:36:44.0

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容器有这个名字的beanboolean 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类型@NullableClass<?> 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);// 绑定完成 2return (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揭秘》

  相关解决方案