1.概述
Spring 框架带有两个 IOC 容器—— BeanFactory和ApplicationContext。BeanFactory是 IOC 容器的最基本版本,ApplicationContext扩展了BeanFactory的特性。
Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。
spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖。
1.1BeanFactory
接口介绍
1.BeanFactory接口:
是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。它最主要的方法就是getBean(String beanName)。
2.BeanFactory的三个子接口:
- HierarchicalBeanFactory:提供父容器的访问功能
- ListableBeanFactory:提供了批量获取Bean的方法
- AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理
3.ConfigurableBeanFactory:
主要单例bean的注册,生成实例,以及统计单例bean
4.ConfigurableListableBeanFactory:
继承了上述的所有接口,增加了其他功能:比如类加载器,类型转化,属性编辑器,BeanPostProcessor,作用域,bean定义,处理bean依赖关系, bean如何销毁…
5.实现类DefaultListableBeanFactory详细介绍:
实现了ConfigurableListableBeanFactory,实现上述BeanFactory所有功能。它还可以注册BeanDefinition
接口详细介绍请参考:揭秘BeanFactory
接口具体说明
1、BeanFactory作为一个主接口不继承任何接口,暂且称为一级接口。
2、有3个子接口继承了它,进行功能上的增强。这3个子接口称为二级接口。
3、ConfigurableBeanFactory可以被称为三级接口,对二级接口HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口SingletonBeanRegistry
4、ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,称为四级接口。(这4级接口是BeanFactory的基本接口体系。继续,下面是继承关系的2个抽象类和2个实现类)
5、AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBeanFactory大部分功能。
6、AbstractAutowireCapableBeanFactory同样是抽象类,继承自AbstractBeanFactory,并额外实现了二级接口AutowireCapableBeanFactory
7、DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory,实现了最强大的四级接口ConfigurableListableBeanFactory,并实现了一个外来接口BeanDefinitionRegistry,它并非抽象类。
8、最后是最强大的XmlBeanFactory,继承自DefaultListableBeanFactory,重写了一些功能,使自己更强大。
1、BeanFactory作为一个主接口不继承任何接口,暂且称为一级接口。
2、有3个子接口继承了它,进行功能上的增强。这3个子接口称为二级接口。
3、ConfigurableBeanFactory可以被称为三级接口,对二级接口HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口SingletonBeanRegistry
4、ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,称为四级接口。
(这4级接口是BeanFactory的基本接口体系。继续,下面是继承关系的2个抽象类和2个实现类:)
5、AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBeanFactory大部分功能。
6、AbstractAutowireCapableBeanFactory同样是抽象类,继承自AbstractBeanFactory,并额外实现了二级接口AutowireCapableBeanFactory
7、DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory,实现了最强大的四级接口ConfigurableListableBeanFactory,并实现了一个外来接口BeanDefinitionRegistry,它并非抽象类。
8、最后是最强大的XmlBeanFactory,继承自DefaultListableBeanFactory,重写了一些功能,使自己更强大。
源码说明
public interface BeanFactory {
/**
* 用来引用一个实例,或把它和工厂产生的Bean区分开,就是说,如果一个FactoryBean的名字为a,那么,&a会得到那个Factory
*/
String FACTORY_BEAN_PREFIX = "&";
/*
* 四个不同形式的getBean方法,获取实例
*/
Object getBean(String name) throws BeansException;
T> T getBean(String name, ClassT> requiredType) throws BeansException;
T> T getBean(ClassT> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
// 根据名称判断bean是否存在
boolean containsBean(String name);
// 是否为单实例Bean
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 是否为原型(多实例)
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 名称、类型是否匹配
boolean isTypeMatch(String name, Class?> targetType)
throws NoSuchBeanDefinitionException;
// 获取类型
Class?> getType(String name) throws NoSuchBeanDefinitionException;
// 根据实例的名字获取实例的别名
String[] getAliases(String name);
}
2.延迟加载与立即加载
BeanFactory按需加载 bean,而ApplicationContext在启动时加载所有 bean。
因此, BeanFactory与 ApplicationContext相比是轻量级的。例子如下:
2.1.使用BeanFactory延迟加载
假设我们有一个名为Student的单例 bean类,它有一个方法:
public class Student {
public static boolean isBeanInstantiated = false;
public void postConstruct() {
setBeanInstantiated(true);
}
//standard setters and getters
}
我们将 在BeanFactory配置文件ioc-container-difference-example.xml中将*postConstruct()*方法定义为init-method:
bean id="student" class="com.baeldung.ioccontainer.bean.Student"
init-method="postConstruct"/>
现在,让我们编写一个测试用例,创建一个BeanFactory来检查它是否加载了Student bean:
@Test
public void whenBFInitialized_thenStudentNotInitialized() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
BeanFactory factory = new XmlBeanFactory(res);
assertFalse(Student.isBeanInstantiated());
}
在这里,Student对象没有被初始化。换句话说,只有BeanFactory被初始化。只有当我们显式调用getBean()方法时,我们的BeanFactory中定义的 bean才会被加载*。*
让我们检查一下我们手动调用getBean()方法的Student bean的初始化:
@Test
public void whenBFInitialized_thenStudentInitialized() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
BeanFactory factory = new XmlBeanFactory(res);
Student student = (Student) factory.getBean("student");
assertTrue(Student.isBeanInstantiated());
}
在这里,Student bean 加载成功。因此,BeanFactory仅在需要时才加载 bean。
2.2. 使用ApplicationContext预加载
现在,让我们使用ApplicationContext代替BeanFactory。
我们将只定义*ApplicationContext,*它会通过使用立即加载策略立即加载所有 bean:
@Test
public void whenAppContInitialized_thenStudentInitialized() {
ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
assertTrue(Student.isBeanInstantiated());
}
在这里,即使我们没有调用getBean()方法,也会创建Student对象。
ApplicationContext被认为是一个沉重的 IOC 容器,因为它的预先加载策略会在启动时加载所有 bean。相比之下, BeanFactory是轻量级的,可以在内存受限的系统中使用。尽管如此,我们最常用的仍是ApplicationContext。
3.ApplicationContext
ApplicationContext以更加面向框架的风格增强了BeanFactory,并提供了一些适用于企业应用程序的特性。
-
默认初始化所有的Singleton,也可以通过配置取消预初始化。
-
继承MessageSource,因此支持国际化。
-
资源访问,比如访问URL和文件。
-
事件传播特性,即支持aop特性。
-
同时加载多个配置文件。
-
以声明式方式启动并创建Spring容器。
ApplicationContext:是IOC容器另一个重要接口, 它继承了BeanFactory的基本功能, 同时也继承了容器的高级功能,如:MessageSource(国际化资源接口)、ResourceLoader(资源加载接口)、ApplicationEventPublisher(应用事件发布接口)等。
4. BeanFactoryPostProcessor和BeanPostProcessor的自动注册
ApplicationContext在启动时会**自动注册BeanFactoryPostProcessor和****BeanPostProcessor 。**另一方面,BeanFactory不会自动注册这些接口。
4.1.在BeanFactory中注册
为了理解,让我们编写两个类。
首先,我们有CustomBeanFactoryPostProcessor类,它实现了BeanFactoryPostProcessor:
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static boolean isBeanFactoryPostProcessorRegistered = false;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
setBeanFactoryPostProcessorRegistered(true);
}
// standard setters and getters
}
在这里,我们重写了postProcessBeanFactory() 方法来检查它的注册。
其次,我们有另一个类CustomBeanPostProcessor,它实现了BeanPostProcessor:
public class CustomBeanPostProcessor implements BeanPostProcessor {
private static boolean isBeanPostProcessorRegistered = false;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName){
setBeanPostProcessorRegistered(true);
return bean;
}
//standard setters and getters
}
在这里,我们重写了postProcessBeforeInitialization()方法来检查它的注册。
此外,我们在ioc-container-difference-example.xml配置文件中配置了这两个类:
bean id="customBeanPostProcessor"
class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor" />
bean id="customBeanFactoryPostProcessor"
class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor" />
让我们看一个测试用例来检查这两个类是否在启动时自动注册:
@Test
public void whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);
assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}
从我们的测试中可以看出,自动注册没有发生。
现在,让我们看一个在BeanFactory中手动添加它们的测试用例:
@Test
public void whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);
CustomBeanFactoryPostProcessor beanFactoryPostProcessor
= new CustomBeanFactoryPostProcessor();
beanFactoryPostProcessor.postProcessBeanFactory(factory);
assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
CustomBeanPostProcessor beanPostProcessor = new CustomBeanPostProcessor();
factory.addBeanPostProcessor(beanPostProcessor);
Student student = (Student) factory.getBean("student");
assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}
在这里,我们使用postProcessBeanFactory()方法注册CustomBeanFactoryPostProcessor和addBeanPostProcessor()方法注册CustomBeanPostProcessor。在这种情况下,他们俩都成功注册。
4.2. 在ApplicationContext中注册
正如我们前面提到的,ApplicationContext会自动注册这两个类,而无需编写额外的代码。
让我们在单元测试中验证此行为:
@Test
public void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically() {
ApplicationContext context
= new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}
如我们所见,在这种情况下**,两个类的自动注册都是成功的。**
因此,始终建议使用ApplicationContext,因为 Spring 2.0(及更高版本)大量使用BeanPostProcessor。
还值得注意的是,如果您使用的是普通的BeanFactory,那么事务和 AOP 等功能将不会生效(至少在不编写额外代码行的情况下不会生效)。这可能会导致混淆,因为配置看起来没有任何问题。
5. 结论
-
BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。
-
ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:
a. 国际化支持
b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
c. 事件传递:通过实现ApplicationContextAware接口。 -
常用的获取ApplicationContext
FileSystemXmlApplicationContext:从文件系统或者url指定的xml配置文件创建,参数为配置文件名或文件名数组,有相对路径与绝对路径。
ApplicationContext factory=new FileSystemXmlApplicationContext("src/applicationContext.xml");
ApplicationContext factory=new FileSystemXmlApplicationContext("E:/Workspaces/MyEclipse 8.5/Hello/src/applicationContext.xml");
ClassPathXmlApplicationContext:从classpath的xml配置文件创建,可以从jar包中读取配置文件。ClassPathXmlApplicationContext 编译路径总有三种方式:
ApplicationContext factory = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext factory = new ClassPathXmlApplicationContext("file:E:/Workspaces/MyEclipse 8.5/Hello/src/applicationContext.xml");
XmlWebApplicationContext:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现
org.springframework.web.context.ContextLoaderListener
或
context
org.springframework.web.context.ContextLoaderServlet
1
这两种方式都默认配置文件为web-inf/applicationContext.xml,也可使用context-param指定配置文件
contextConfigLocation
/WEB-INF/myApplicationContext.xml