BeanFactory介绍
Spring通过一个配置文件描述Bean及Bean之间的依赖关系,利用Java语言的反射子功能实例化Bean并建立Bean之间的依赖关系。Spring的IoC容器在完成这些底层工作的基础上,还提供Bean实例缓存、生命周期管理、Bean实例代理、时间发布、资源装载等高级服务。
- Bean工厂 — com.springframework.beans.factory.BeanFactory是Spring框架最核心的接口,他提供了高级IoC的配置机制。BeanFactory是管理不同类型的Java对象成为可能。
- 应用上下文 — com.springframework.context.ApplicationContext建立在BeanFactory基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架时间体系,更易于创建市级应用。
我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。但有时为了行文方便,我们也将ApplicationContext称为Spring容器。
对于二者的用途,我们可以进行很简单划分:BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都可以直接使用ApplicationContext而非底层的BeanFactory。
BeanFactory
诚如其名,BeanFactory是一个类工厂,但和传统的类工厂不同,传统的类工厂斤负责构造一个或几个类的实例;而BeanFactory是类的通用工厂,他可以创建并管理各种类的对象。这些可被创建和管理的对象本身没有什么特别之处,仅是一个POJO,Spring称这些被创建和管理的Jaba对象为Bean。我们知道JavaBean是要满足一定规范的,如唏嘘提供一个默认不带参的构造函数、不依赖于某一特定的容器等,但Spring中所说的Bean比JavaBean更宽泛一些,所有可以被Spring容器实例化并管理的Java类都可以称为Bean
BeanFactory的类体系结构
Spring为BeanFactory提供了多种实现,最常用的是XmlBeanFactory,但在Spring3.2中已经废弃,建议使用XmlBeanDefinitionReader、DefaultListableBeanFactory代替。BeanFactory的类继承体系设计优雅,堪称经典、通过继承体系,我们可以很容易地了解到BeanFactory具有哪些功能,如下图所示:
BeanFactory接口位于类结构树的顶端,它最主要的方法就是getBean(String beanName),该方法从容其中返回特定名称的Bean。BeanFactory的功能通过其它接口得到不断拓展。下面对上图中设计的其他接口分别进行说明。
- ListableBeanFactory:该接口定义了访问容器中Bean基本信息的若干方法,如查看Bean的个数、获取某一类型Bean的配置名、查看容器中是否包括某一Bean等。
- HireachicalBeanFactory:父子级联IoC容器的接口,自容器可以通过接口方法访问父容器。
- ConfigurableBeanFactory:这是一个重要的接口,增强了IoC容器的可定制型。它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法。
- AutowireCapableBeanFactory:定义了将容器中的Bean按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法。
- SingletonBeanFactory:定义了允许在运行期向容器注册单实例Bean的方法。
- BeanDefinitionRegistry:Spring配置文件中每一个bean节点元素在Spring容器里都通过一个BeanDefinition对象表示,它描述了Bean的配置信息。而BeanDefinitionRegistry接口提供了向容器手工注册BeanDefinition对象的方法。
初始化BeanFactory
下面使用Spring配置文件为Car提供配置信息,然后通过BeanFactory装在配置文件,启动SpringIoC容器。Spring配置文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car1" class="com.smart.Car"
p:brand="Cadillac CT6"
p:color = "白色"
p:maxSpeed="320">
</bean>
</beans>
下面通过XmlBeanDefinitionReader、DefaultListableBeanFactory实现类启动SpringIoC容器,如下所示:
public class BeanFactoryTest {
public void getBean() throws IOException {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource res = resolver.getResource("classpath:resource/spring-config.xml");
System.out.println(res.getURL());
// 废弃,不建议使用
// BeanFactory bf = new XmlBeanFactory(res);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
System.out.println("init BeanFactory.");
Car car = factory.getBean("car",Car.class);
System.out.println("Car bean is ready for use!");
car.introduce();
}
public static void main(String[] args) throws IOException {
BeanFactoryTest beanFactoryTest = new BeanFactoryTest();
beanFactoryTest.getBean();
}
}
结果如下:
XmlBeanDefinitionReader通过Resource装载Spring配置信息并启动IoC容器,然后就可以通过BeanFactory #getBean(beanName) 方法从IoC容器中获取Bean。
总结
- 我们研究BeanFactory的类体继承体系设计优雅,不仅仅为了研究Spring,更要了解其中设计的思想。
- BeanFactory的体系结构中我们经常使用的是XmlBeanDefinitionReader、DefaultListableBeanFactory。其中ConfigurableBeanFactory接口增强了IoC容器可定制性。
- 通过BeanFactory启动IoC容器时,并不会初始化配置文件中定义的Bean,初始化动作发生在第一个调用时。对于单实例(singleton)的Bean来说,BeanFactory会缓存Bean实例,所以第二次使用getBean()获取Bean时,将直接从IoC容器的缓存中获取Bean实例。
- Spring在DefaultSingletonBeanRegistry类中提供了一个用于缓存单实例Bean的缓存器,他是一个用HashMap实现的缓存器,单实例的Bean以beanName为键保存在这个HashMap中。
- 在初始化BeanFactory时,必须为其提供一种日志框架。