ApplicationContext可以被看作Spring的容器,它是继承自BeanFactory的。BeanFactory是访问容器的根接口,提供了必要的配置框架和基础功能,而ApplicationContext提供了更多的企业级功能和更加丰富的功能。
1 容器概览
org.springframework.context.ApplicationContext接口代表了SpringIoC容器,它用于实例化、配置和组合bean。通过读取配置元数据,容器就能获取到实例化、配置和组合对象的指令。XML、注解或Java代码中可以存在配置元数据。
Spring提供了几种“开箱即用”的ApplicationContext接口实现。在单独的应用程序中,创建一个ClassPathXmlApplicatlionContext或FileSystemXmlApplicationContext的实例是很普遍的。不过,在大部分应用场景中,不需要显式地实例化一个或多个IoC实例。
应用系统的类和配置元数据是结合在一起的,所以在ApplicationContext创建和初始化之后,应用系统就已经配置完毕且可以执行了。
2 配置元数据
IoC容器采用配置元数据的方式。这种配置元数据表明了容器需要如何实例化、配置和组织对象。
Spring配置至少包含一个bean定义。由基于XML的配置元数据可知,顶层<beans><beans/>中配置的即为bean元素。Java配置通常在一个类中使用@Bean注解方法。
这些根据实际对象定义的bean组成了应用程序。特别是在定义服务层对象、数据访问层对象(DAO)、表现层对象(比如Struts的Action实例)等时候。
下面的例子说明了一个基于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="..." class="..."> <!—属性和配置 --> </bean> <bean id="..." class="..."> <!—属性和配置 --> </bean> <!—更多的bean定义--> </beans>
id属性是一个用来识别各个bean定义的字符串。class属性定义了bean的类型,而且使用类名的全称。id属性的值引用的是对象。
3 容器的实例化
Spring容器的实例化过程很直接,传递给ApplicationContext构造器的参数即为配置元数据相关资源的路径。
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
下面的例子即为服务层对象services.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"> <!-- services --> <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl"> <property name="accountDao" ref="accountDao"/> <property name="itemDao" ref="itemDao"/> <!—其它属性和配置 --> </bean> <!—更多bean定义 --> </beans>
下面即为数据访问对象daos.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="accountDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao"> <!—其它属性和配置--> </bean> <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao"> <!--其它属性和配置--> </bean> <!—更多bean定义 --> </beans>
在前述例子中,服务层包含类PetStoreServiceImpl,以及两个数据访问对象JpaAccountDao和JpaItemDao。name属性表示bean的名称,ref属性表示引用另一个bean的名字。id和ref的关系即为依赖关系。
在一个庞大的系统中,如果将所有的bean定义存放在一个xml文件中,那么维护起来将是一场噩梦。Spring提供了一种方式可以解决这个问题,即将不同业务层的配置文件放到不同的xml文件中,然后在一个xml文件中引入其它所有的配置文件。main.xml示例如下:
<beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>
这个例子中,从三个文件里引入了外部bean定义:services.xml,messageSource.xml和themeSource.xml。所有的路径都是相对于main.xml的,因此services.xml必须与main.xml在相同路径下,而其它两个xml文件所在的文件夹resources路径必须与main.xml相同。可见,前面的那一个斜杠被忽略了,因为这里必须是相对路径,最好不要在路径前面加上斜杠。
4 容器的使用
ApplicationContext是一个高级工厂接口,它维护着不同的bean及其依赖的注册。使用T getBean(String name, Class<T> requiredType)可以查询到已实例化的bean。可以通过ApplicationContext来读取和访问定义的bean。
// 创建和配置bean
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
// 查询配置的实例
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// 使用配置的实例
List<String> userList = service.getUsernameList();
getBean用来查询bean实例,ApplicationContext还有其它查询bean实例的方法,理想情况下你不会用到它们。实际上,应用代码中不应该有getBean方法,这样就不用依赖Spring的API,比如Spring与Web框架的集成就提供了相应的依赖注入,而不需要显式地去调用getBean方法。