7.4.2 使用ApplicationContext

7.4.2 使用ApplicationContext

大部分时候,都不会使用BeanFactory实例作为Spring容器,而是使用ApplicationContext实例作为容器,因此Spring容器也称为Spring上下文。 ApplicationContext作为BeanFactory的子接口,增强了BeanFactory的功能。
ApplicationContext允许以声明式方式操作容器,无须手动创建它。可利用如ContextLoader的支持类,在Web应用启动时自动创建ApplicationContext。当然也可采用编程方式创建ApplicationContext.

ApplicationContext额外功能

除了提供BeanFactory所支持的全部功能外, ApplicationContext还有如下额外的功能。

  1. ApplicationContext默认会预初始化所有的singleton Bean,也可通过配置取消预初始化ApplicationContext继承MessageSource接口,因此提供国际化支持。
  2. 资源访问,比如访问URL和文件。
  3. 事件机制。
  4. 同时加载多个配置文件。
  5. 以声明式方式启动并创建Spring容器。

ApplicationContext包括BeanFactory的全部功能,因此建议优先使用ApplicationContext。除非对于某些内存非常关键的应用,才考虑使用BeanFactory.

程序示例

项目结构

例如有如下配置。

beans.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 如果不加任何特殊的配置,该Bean默认是singleton行为的 -->
<bean id="chinese" class="org.crazyit.app.service.Person">
<!-- 驱动Spring执行chinese Bean的setTest()方法,以"孙悟空"为传入参数 -->
<property name="test" value="孙悟空" />
</bean>
</beans>

上面粗体字代码配置了一个idchinesebean,如果没有任何特殊配置,该Bean就是singleton Bean,ApplicationContext会在容器初始化完成后,自动调用Person类的构造器创建chinese这个Bean,并以"孙悟空"这个字符串作为传入参数去调用chinese这个beansetTest方法。

Person.java

该程序用的Person类的代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.crazyit.app.service;

public class Person
{
public Person()
{
System.out.println("==正在执行Person无参数的构造器==");
}
public void setTest(String name)
{
System.out.println("正在调用setName()方法,传入参数为:" + name);
}
}

测试

即使主程序只有如下一行代码:

1
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

上面代码只是使用ApplicationContext创建了Spring容器, ApplicationContext会自动预初始化容器中的chinese这个bean包括:

  1. 调用它的无参数的构造器,
  2. 根据< property.>元素执行setter方法。

执行上面代码,可以看到如下输出:

1
2
==正在执行Person无参数的构造器==
正在调用setName()方法,传入参数为:孙悟空

如果将main方法中创建Spring容器的代码换成使用BeanFactory作为容器,例如改为如下代码:

1
2
3
4
5
6
// 搜索类加载路径下的beans.xml文件创建Resource对象
Resource isr = new ClassPathResource("beans.xml");
// 创建默认的BeanFactory容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 让默认的BeanFactory容器加载默认的
new XmlBeanDefinitionReader(beanFactory).loadBeanDefinitions(isr);

上面代码以BeanFactory创建了Spring容器,但**BeanFactory不会预初始化容器中的Bean**,因此执行上面代码不会看到调用Person类的构造器、执行chinese这个beansetName方法。

如何阻止Spring容器预初始化Bean

为了阻止Spring容器预初始化容器中的singleton Bean,可以**为<bean>元素指定lazy-init="true"属性,该属性用于阻止容器预初始化该Bean**。因此,如果为上面<bean>元素指定了lazy-init="true",那么即使使用ApplicationContext作为Spring容器, Spring也不会预初始化该singleton Bean.