共计 5376 个字符,预计需要花费 14 分钟才能阅读完成。
1. 引言
Spring 框架附带了两个 IOC 容器– BeanFactory 和 ApplicationContext. BeanFactory是 IOC 容器的最根本版本,ApplicationContext扩大了 BeanFactory 的性能。
那么本篇文章中,咱们将通过理论例子理解这两个 IOC 容器之间的显著差别。
2. 提早加载 vs. 预加载
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
}
咱们将把 postConstruct() 办法定义为 BeanFactory 配置文件 ioc-container-difference-example.xml 中的 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 才会被加载。
让咱们检查一下 Student bean 的初始化状况,咱们手动调用 getBean() 办法:
@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 以更面向框架的格调加强了BeanFactory,并提供了一些实用于企业应用程序的性能。
例如,它提供了消息传递(i18n 或国际化)性能、事件公布性能、基于正文的依赖注入,以及与 Spring AOP 个性的简略集成。
除此之外,ApplicationContext简直反对所有类型的 bean 作用域,然而 BeanFactory 只反对两个作用域——Singleton和Prototype。因而,在构建简单的企业应用程序时,最好应用ApplicationContext。
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
}
这里,咱们重写了 PostProcessBeforeAlization() 办法来查看其注册。
另外,咱们在 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,因为 Spring2.0(及更高版本)大量应用 BeanPostProcessor。
还有一点值得注意的是 如果应用的是一般的 BeanFactory,那么事务和 AOP 之类的性能将不会失效(除非你编写额定的代码实现,那就另当别论了)。这样可能会导致代码很凌乱,因为配置看起来貌似没故障。
5. 写在结尾
ApplicationContext 提供了一些高级性能,包含一些面向企业应用程序的性能,而 BeanFactory 只提供了基本功能。因而,个别倡议应用 ApplicationContext,只有在内存耗费十分要害的状况下,咱们才应该思考去应用 BeanFactory。
如果你感觉文章还不错,记得关注公众号:锅外的大佬
刘一手的博客