【Spring系列】- BeanFactory
文章目录
一、BeanFactory引入后
BeanFactory可以完成作为IoC Service Provider的所有职责,包括业务对象的注册和对象间依赖关系的绑定。将所需业务对象交给BeanFactory后,就可以直接从BeanFactory取得已组装完成并可用的对象
引入BeanFactory后,唯一不同的是对象之间依赖关系的解决方式改变了。之前系统业务对象需要自己去“拉”所依赖的业务对象,有了BeanFactory之类的IoC容器之后,需要依赖什么让BeanFactory推过来就行了。所以,简单点儿说,拥有BeanFactory之后,要使用IoC模式进行系统业务对象的开发。
-
BeanFactory通常用XML文件来注册并管理各业务对象之间的依赖关系
-
不用BeanFactory时,通常需要直接在应用程序的入口类的main方法中,自己实例化相应的对象并调用之
-
有了BeanFactory,只需将“生产线图纸”交给BeanFactory,让BeanFactory为我们生产一个FxNewsprovider
BeanFactory container = new XmlBeanFactory(new ClassPathResource("配置文件路径")); // 或 ApplicationContext container = new ClassPathXmlpplicationContext("配置文件路径"); // 或 ApplicationContext container = new FileSystemXmlApplicationContext("配置文件路径"); // 上面的三选一,再加上下面的两行 FXNewsProvider newsProvider = (FxNewsProvider)container.getBean("djNewsProvider"); newsProvider.getAndPersistNews();
二、BeanFactory的对象注册与依赖绑定方式
BeanFactory作为一个IoC Service Provider,同样需要某种途径来记录和管理各个业务对象以及业务对象之间的依赖绑定关系。而BeanFactory支持所有三种方式
1. 直接编码方式
- BeanFactory接口只定义了用于访问容器内Bean的方法,需要具体的实现类来负责实际的Bean的注册和管理。DefaultListableBeanFactory就是一个比较通用的BeanFactory实现类。DefaultListableBeanFactory还实现了BeanDefinitionRegistry接口,该接口负责管理Bean的注册,通常具体的BeanFactory实现类都会实现这个接口。
-
每一个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之相对应,该BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性等。当客户端向BeanFactory请求相应对象的时候,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。RootBeanpefinition和childBeanDefinition是BeanDefinition的两个主要实现类。
-
绑定代码:
public static void main(String[] args){ // 在main方法中,首先构造一个DefaultListableBeanFactory作为BeanDefinitionRegistry DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory(); // 将其交给bindViaCode方法进行具体的对象注册和依赖管理,返回需要的IoC对象 BeanFactory container = (BeanFactory)bindViaCode(beanRegistry); // getBean获取Bean对象,执行对象方法 FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider"); newsProvider.getAndPersistNews(); } public static BeanFactory bindViaCode (BeanDefinitionRegistry registry){ // 构造BeanDefinition,针对不同业务构造相应的BeanDefinition // 使用RootBeanDefinition作为BeanDefinition的实现类 AbstractBeanDefinition newsProvider = new RootBeanDefinition( FXNewsProvider.class, true); AbstractBeanDefinition newsListener = new RootBeanDefinition( DowJonesNewsListener.class, true); AbstractBeanDefinition newsPersister = new RootBeanDefinition( DowJonesNewsPersister.class, true); // 将bean定义注册到容器中 // 将BeanDefinition注册到BeanDefinitionRegistry容器registry中 registry.registerBeanDefinition("diNewsProvider", newsProvider); registry.registerBeanDefinition("djListener",newsListener); reqistry.reqisterBeanDefinition("diPersister",newsPersister); // 指定依赖关系 //1.可以通过构造方法注入方式 // 通过ConstructorArgumentValues为其注入相关依赖 ConstructorArqumentValues argValues = new ConstructorArqumentValues(); argValues.addIndexedArqumentValue(0, newsListener); arqValues.addIndexedArqumentValue(1, newsPersister); newsProvider.setConstructorArqumentValues(argValues); //2.或者通过setter方法注入方式 MutablePropertyValues propertyValues = new MutablePropertyValues(); propertyValues.addPropertyValue(new ropertyValue("newsListener" ,newsListener)); propertyValues.addPropertyValue(new PropertyValue("newPersistener",newsPersister); newsProvider.setPropertyValues(propertyValues); // 绑定完成后,返回注册并绑定了所有业务对象的BeanDefinitionReqistry容器实例 return (BeanFactory)registry; }
需要注意最后return部分,因为传入的DefaultListableBeanFactory同时实现了BeanFactory和BeanDefinitionRegistry接口,所以这样强转不会出现问题
2. 外部配置文件方式
-
Spring的IoC容器支持两种配置文件格式:Properties文件格式和XML文件格式
-
根据不同的外部配置文件格式,给出相应的BeanDefinitionReader实现类,由它负责将相应的配置文件内容读取并映射到BeanDefinition,然后将映射后的BeanDefinition注册到一个BeanDefinitionRegistry,即完成Bean的注册和加载
-
大部分工作,包括解析文件格式、装配BeanDefinition,都是由BeanDefinitionReader的实现类来做的,BeanDefinitionRegistry只负责保管而已
BeanDefinitionRegistry beanRegistry = <某个BeanDefinitionRegistry实现类,通常为DefaultListableBeanFactory>; BeanDefinitionReader beanDefinitionReader=new BeanDefinitionReaderImpl(beanRegistry); beanDefinitionReader.loadBeanDefinitions("配置文件路径"); //现在我们就取得了一个可用的BeanDefinitionRegistry实例
Properties配置格式的加载
Spring提供了org.springframework.beans .factory.support .PropertiesBeanDefinitionReader类用于Properties格式配置文件的加载,根据该类的读取规则,提供Properties配置文件即可
之后就可以将这些对象之间的注册和依赖注入信息加载到BeanFactory中使用了
所有的信息配置到Properties文件即可,不用再通过冗长的代码来完成对象的注册和依赖绑定,交给相应的BeanpefinitionReader,这里是PropertiesBeanDefinitionReader来做就行
public static void main(string[] args){
DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
BeanFactory container =(BeanFactory)bindViaPropertiesFile(beanRegistry);
FXNewsProvider newsProvider =(FXNewsProvider)container.getBean("diNewsProvider" );
newsProvider.getAndPersistNews();
}
public static BeanFactory bindViaPropertiesFile(BeanDefinitionRegistry registry){
PropertiesBeanDefinitionReader reader = new
PropertiesBeanDefinitionReader(registry);
reader.loadBeanDefinitions("classpath:../../binding-config.properties");
return (BeanFactory)registry;
XML配置格式的加载
XML配置格式是Spring支持最完整,功能最强大的表达方式
与为Properties配置文件格式提供propertiesBeanDefinitionReader相对应,Spring同样为XMI格式的配置文件提供了现成的BeanDefinitionReader实现,即XmlBeanDefinitionReader。XmlBeanDefinitionReader负责读取Spring指定格式的XML配置文件并解析,之后将解析后的文件内容映射到相应的BeanDefinition,并加载到相应的BeanDefinitionRegistry中
public static void main(string[] args){
DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
BeanFactory container = (BeanFactory)bindViaXMFile(beanRegistry);
FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("diNewsProvider");
newsProvider.getAndPersistNews();
}
public static BeanFactory bindViaXMLFile(BeanDefinitionRegistry registry){
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("classpath:../news-config.xml");
return (BeanFactory)registry;
//或者直接return new XmlBeanFactory(new ClassPathResource("../news-config.xml"));
}
3. 注解方式
-
BeanFactory几乎支持IoC Service Provider可能使用的所有方式,之所以这么说,有两个原因:
- 在Spring2.5发布之前,Spring框架并没有正式支持基于注解方式的依赖注入
- Spring2.5发布的基于注解的依赖注入方式,如果不使用classpath-scanning功能的话,仍然部分依赖于“基于XML配置文件”的依赖注入方式
-
如果要通过注解标注的方式为FxNewsProvider注入所需要的依赖,可以使用@Autowired以及@Component对相关类进行标记
@Autowired
告知Spring容器需要为当前对象注入哪些依赖对象@component
则是配合Spring 2.5中新的classpath-scanning功能使用的
@Component public class FXNewsProvider{ @Autowired private IFXNewsListenernewsListener; @Autowired private IFXNewsPersister newPersistener; public FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister){ this.newsListener= newsListner; this.newPersistener=newsPersister; } ... } @Component public class DowonesNewsListenerimplements IFXNewsListener {...} @Component public class DowJonesNewsPersister implements IFXNewsPersister {...}
-
现在我们只要再向Spring的配置文件中增加一个“触发器”,配置使用classpath-scanning功能。
<context:component-scan/>
会到指定的包(package)下面扫描标注有@Component
的类,如果找到,则将它们添加到容器进行管理,并根据它们所标注的@Autowired
为这些类注入符合条件的依赖对象
-
之后就可以像通常那样加载配置并执行当前应用程序了
public static void main(string[] args){ ApplicationContext ctx= new ClassPathXmlApplicationContext("配置文件路径"); FXNewsProvider newsProvider =(FXNewsProvider)container.getBean("FXNewsProvider"); newsProvider.getAndPersistNews(); }