Spring 系列 - IoC 容器
Last updated: Oct 219, 21029
问
Spring 的 IoC 容器有哪些?
如何使用 BeanFactory?
BeanFactory 是如何进行 对象注册 和 对象间的依赖管理 的?
答
Spring 中的 IoC 容器
- Spring 中的 IoC 容器是一个 IoC Service Provider
- 不仅仅是 IoC Service Provider,还提供了 IoC 之外的支持
这些支持包括:AOP 框架支持、企业级服务支持等等
Spring 提供了两种容器类型
- BeanFactory
- ApplicationContext
BeanFactory
是基础类型的 IoC 容器,提供完整的 IoC 服务支持
采用 延迟初始化(Lazy-load) 策略
即只有在需要某个对象时,才初始化依赖对象,并进行依赖注入操作
容器初期启动速度较快,所需资源有限
适用场景:资源有限
ApplicationContext
继承自 BeanFactory,构建在 BeanFactory 之上,相对高级的容器实现
扩展了其他功能,如事件发布、国际化信息支持等
采用 全部初始化并绑定 策略
容器初期启动速度较慢,要求更多的资源
适用场景:资源充足,并要求更多功能
BeanFactory 的使用
FXNewsProvider 的业务代码
public class FXNewsProvider {
private IFXNewsListener listener;
private IFXNewsPersister persister;
public FXNewsProvider(IFXNewsListener listener, IFXNewsPersister persister) {
this.listener = listener;
this.persister = persister;
}
public void getAndPersistNews() {
System.out.println("获取新闻,并保存");
}
public void setListener(IFXNewsListener listener) {
this.listener = listener;
}
public void setPersister(IFXNewsPersister persister) {
this.persister = persister;
}
}
IFXNewsListener 和 IFXNewsPersister 及它们的实现类
public interface IFXNewsListener {
}
public class DowJonesNewsListener implements IFXNewsListener {
}
public interface IFXNewsPersister {
}
public class DowJonesNewsPersister implements IFXNewsPersister {
}
没有 BeanFactory,我们会这样写:
public static void main(String[] args) {
IFXNewsListener newsListener = new DowJonesNewsListener();
IFXNewsPersister newsPersister = new DowJonesNewsPersister();
FXNewsProvider newsProvider = new FXNewsProvider(newsListener, newsPersister);
newsProvider.getAndPersistNews();
}
有了 BeanFactory,我们会这样写:
注册对象和 依赖关系的 XML 文件 fxnews.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="djNewsProvider" class="main.FXNewsProvider">
<constructor-arg index="0">
<ref bean="djNewsListener"/>
</constructor-arg>
<constructor-arg index="1">
<ref bean="djNewsPersister"/>
</constructor-arg>
</bean>
<bean id="djNewsListener" class="main.DowJonesNewsListener"/>
<bean id="djNewsPersister" class="main.DowJonesNewsPersister"/>
</beans>
public static void main(String[] args) {
BeanFactory container = new XmlBeanFactory(new ClassPathResource("resources/fxnews.xml"));
FXNewsProvider newsProvider = (FXNewsProvider) container.getBean("djNewsProvider");
newsProvider.getAndPersistNews();
}
比较
有了 BeanFactory 这样的 IoC 容器后
- 需要依赖什么对象,直接让 BeanFactory 推过来
- 业务对象 不用拉 所依赖的业务对象
BeanFactory 注册对象 和 管理依赖
在 前面 一章中介绍了 IoC Service Provider 创建对象并管理依赖关系的几种方式
那在 BeanFactory 中具体是如何实现这些的呢?
概念
BeanFactory
是一个接口
只定义了如何访问容器管理的 Bean 的方法
BeanDefinition
每一个业务对象,在容器中都有一个 BeanDefinition 的实例与之对应
BeanDefinition 的实例保存对象的所有必要信息
BeanFactory 通过保存的这些信息,返回一个完备可用的对象实例
BeanDefinitionRegistry
具体负责 注册管理对象 的工作
编码方式实现
与 通用 IoC Service Provider 相同,提供了三种 注册对象并管理依赖 的方式,
以下展现了 BeanFactory 底层是如何工作的:
package main;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
public class SpringApplication {
public static void main(String[] args) {
DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
BeanFactory container = bindViaCode(beanRegistry);
FXNewsProvider newsProvider = (FXNewsProvider) container.getBean("djNewsProvider");
newsProvider.getAndPersistNews();
}
private static BeanFactory bindViaCode(BeanDefinitionRegistry registry) {
// 为每个业务对象创建一个 BeanDefinition
AbstractBeanDefinition newsProvider = new RootBeanDefinition(FXNewsProvider.class);
AbstractBeanDefinition newsListener = new RootBeanDefinition(DowJonesNewsListener.class);
AbstractBeanDefinition newsPersister = new RootBeanDefinition(DowJonesNewsPersister.class);
// 将每个 BeanDefinition 注册到 BeanDefinitionRegistry 中
registry.registerBeanDefinition("djNewsProvider", newsProvider);
registry.registerBeanDefinition("djListener", newsListener);
registry.registerBeanDefinition("djPersister", newsPersister);
// 进行对象的依赖注入操作,如下是 构造方法注入 的方式
ConstructorArgumentValues argValues = new ConstructorArgumentValues();
argValues.addIndexedArgumentValue(0, newsListener);
argValues.addIndexedArgumentValue(1, newsPersister);
newsProvider.setConstructorArgumentValues(argValues);
// 返回 BeanFactory,以便客户端从中获取相应的对象实例
return (BeanFactory) registry;
}
}
配置文件方式
- PropertiesBeanDefinitionReader 读取 Properties 文件内容,将对象注册到 BeanDefinitionRegistry
- XMLBeanDefinitionReader 读取 XML 文件内容,将对象注册到 BeanDefinitionRegistry
注解方式
@Autowired
告知 Spring 容器需要为 当前对象 注入哪些 依赖对象
@Component
告诉 Spring 容器需要将当前类添加到容器中管理