这是我参与更文挑战的第4天,活动详情查看:更文挑战
BeanFactory的对象注册与依赖绑定方式
与前面提到的IoC的绑定方式类似,也可以分为三种,分别是:直接编码、外部配置、注解。
1.直接编码方式
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.addPropertyValues(new PropertyValue("newsListener", newsListener));
*propertyValues.addPropertyValues(new PropertyValue("newPersister", newsPersister));
newsProvider.setPropertyValues(propertyValues);
**/
//绑定完成
return (BeanFactory)registry;
}
复制代码
BeanFactory只是一个接口,最终需要一个该接口的实现来进行实际的Bean管理,DefaultListableBeanFactory就是这么一个比较通用的BeanFactory实现类。DefaultListableBeanFactory除了间接地实现了BeanFactory接口,还实现了BeanDefinitionRegistry接口,该接口才是在BeanFactory的实现中担当Bean注册管理的角色。基本上,BeanFactory接口只定义如何访问容器内管理Bean的方法,各个BeanFactory的具体实现类负责具体Bean的注册以及管理工作。BeanDefinitionRegistry接口定义抽象了Bean的注册逻辑。通常情况下,具体的BeanFactory实现类会实现这个接口来管理Bean的注册。它们之间的关系如下所示:
现在我们在回头上面这段绑定代码,就有“柳暗花明”的感觉了。
1.在main方法中,首先构造一个DefaultListableBeanFactory作为BeanDefinitionRegistry,然后将其交给bindViaCode方法进行具体的对象注册,最后执行相应逻辑。
2.在bindViaCode方法中,首先针对相应的业务对象构造与其相应的BeanDefinition,使用了RootBeanDefinition作为BeanDefinition的实现类。构造完成后,将这些BeanDefinition注册到通过方法参数传进来的BeanDefinitionRegistry中。之后,因为采用的是构造方法注入,所以需要ConstructorArgumentValues为其注入相关依赖。
2.外部配置文件方式
Spring的IoC容器支持两种配置文件格式:Properties文件格式和XML文件格式。
采用外部配置文件时,Spring的IoC容器有一个统一的处理方式。通常情况下,需要根据不同的外部配置文件格式,给出相应的BeanDefinitionReader实现类,由BeanDefinitionReader的相应实现类负责将相应的配置文件内容读取并映射到BeanDefinition,然后将映射后的BeanDefinition注册到一个BeanDefinitionRegistry,之后,BeanDefinitionRegistry即完成Bean的注册和加载。
对于Properties配置格式的加载,Spring提供了org.springframework.beans.factory.support.PropertiesBeanDefinitionReader类用于Properties配置格式的加载。所以,我们不用自己去实现BeanDefinitionReader,只要根据该类的读取规则,提供相应的配置文件即可。
对于XML配置格式的加载,Spring2.x之前,XML配置文件采用DTD(Document Type Definition)实现文档的格式约束。在2.x之后,引入了XSD(XML Schema Definition)的约束方式。
3.注解方式
使用@Autowired和@Component对相关类进行标记。