目录
Spring Ioc容器和Beans的介绍
本章将介绍Spring框架对控制反转(IoC)的实现,IoC也叫依赖注入(DI),这是对象借以明确其依赖的手段,具体可以通过构造器参数、工厂方法、属性设置(所设置的对象可以通过构造器或者工厂方法进行创建)。容器在创建Bean时会注入这些依赖,该过程从根本上反转了对象通过构造方法或服务定位方式来实例化其依赖的方式。
org.springframework.beans
和 org.springframework.context这两个包是Spring IoC容器的基础,BeanFactory接口提供对于任意对象的配置管理功能,ApplicationContext是它的子类,添加了如下功能:
- 于Spring AOP更容易集成
- 消息资源处理(用于国际化)
- 事件发布
- 应用层具体的上下文,如用于web应用的WebApplicationContext
简单来说,BeanFactory提供了配置框架和基本功能,ApplicationContext则添加更多企业专有功能。
在Spring中,形成应用支柱及由Spring IoC容器管理的对象被称为beans,一个bean就是由Spring IoC容器实例化、组装并管理的对象,这些Beans以及它们之间的依赖是由Spring容器配置的元数据来映射的。
容器预览
org.springframework.context.ApplicationContext接口代表Spring IoC容器并负责实例化、配置、组装beans。容器通过读取配置元数据来获取对象实例化、配置、组装的说明,元数据存在于XML、Java注解、Java代码中,这些元数据能够描述构成应用的对象及对象之间的相互依赖。
Spring提供了ApplicationContext的一些实现, 在单一功能的应用中,通常利用ClassPathXmlApplicationContext或FileSystemXmlApplicationContext。XML是传统的用来定义元数据的方式,也可以通过Java注解或Java代码的方式来描述元数据配置,并提供一个少量配置的XML文件来指定这些额外的配置。
下图示出了 Spring运行的一个高层视图,应用涉及的class与Spring的配置绑定,当ApplicationContext被创建并初始化后,应用的配置就完成并可以运行了
配置元数据
如上图所示,Spring IoC容器读取配置元数据,这些配置元数据用以告诉Spring IoC容器如何初始化、配置、组装应用中的对象。传统上,主要是通过XML方式来描述这些元数据,本章也主要通过这种方式来传达Spring IoC容器的特点。
Spring的配置要包括一个或多个需要容器来管理的Bean,XML形式的配置,通过在顶层<beans>元素中通过<bean>来声明这些bean;Java配置方式是在一个具有@Configuration注解的类中通过@Bean注解的方法来声明。
这些Bean定义与应用中的对象相对应,通常而言,主要包括服务层对象、数据访问对象(DAOs)、表现层对象以及Hibernate会话工厂、JMS队列等基础设置对象。通常不需要定义领域对象,其主要是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="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
其中id属性是用来表示该bean定义的字符串,class属性是表示该bean所描述的对象类型的全限定类名。
初始化容器
ApplicationContext构造器接收代表资源路径的字符串,可以从文件系统、Java类路径等外部资源中加载配置。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
如下示出服务层对象的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"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
如下为数据接入层xml配置样例(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">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
在如上的配置实例中,服务层包括PetStoreServiceImpl类和两个JpaAccountDao、
JpaItemDao类型的
数据接入层对象,property name元素引用JavaBean的属性名称,ref引用其他的bean定义的名称。id和ref之间的关联表达了协作对象之间的依赖。
组合XML描述
Bean定义跨多个文件情况,通常一个文件描述一个逻辑分层或模块,你可以通过ApplicationContext构造方法把所有的配置文件作为参数传入,如前面所述,该构造方法是可以接受多个资源位置作为参数的。要不然,也可以在XML文件中通过<import>引入其他的文件,如下所示
<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这三个文件中加载的,加载的文件路径是相对于当前文件而言的。services.xml文件必须在当前文件相同目录下,而messageSource.xml、themeSource.xml文件则是在当前文件所在目录下的resources目录,需要特别注意的是,路径前的"/"是被忽略掉得。因此,考虑到这些路径都是相对的,最好不要在前面加“/”。被引入的文件必须为满足Spring schema的合法的bean定义文件,包括顶层的<beans>元素。
通过"../"来引用父目录中的配置文件的方式是不可取的,这种方式将会依赖应用外部的文件。这种方式用在classpath:中也是不可取的,classpath的配置的改变可能会导致引用文件的路径发生相应的改变,进而可能选择了错误的路径和文件。
你可以只使用绝对的路径来引入其他文件,如file:C:/config/services.xml或classpath:/config/services.xml,不过这种方式会让你的应用与配置的路径有耦合,通常对于这些绝对路径采取间接方式声明,如通过 "${…}"占位符在系统运行时解析JVM系统属性。
Groovy Bean定义DSL
略
容器使用
ApplicationContext是用来维护不同beans和bean之间依赖的一个高级工厂,通过T getBean(String name, Class<T> requiredType)你可以获取想要的bean实例,ApplicationContext可以读取bean定义并获取它们
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
如果是Groovy方式的配置,其步骤是相似的,有一个Groovy配置的上下文实现
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
一个最灵活的方式是通过GenericApplicationContext并结合如XmlBeanDefinitionReader的解析配置的代理
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
当然对于Groovy方式的配置也可以通过GroovyBeanDefinitionReader来解析
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
Spring IoC容器用来管理一个或多个Bean,这些Bean通过提供给容器的配置进行创建。在容器内部,这些Bean定义就是BeanDefinition对象,其包括如下元数据:
- 带包路径的类名:通常是所定义的Bean的具体实现
- Bean有关配置,主要是该Bean在容器中行为方式(包括Scope、生命周期、回调等)
- 该Bean所依赖的其它Bean
- 对于要创建的对象的其它配置,如对于连接池配置的池的大小及连接数目
元数据会转换为BeanDefinition的属性,如下示出相关属性
Property | Explained in… |
---|---|
Class |
|
Name |
|
Scope |
|
Constructor arguments |
|
Properties |
|
Autowiring mode |
|
Lazy initialization mode |