接下来介绍在Spring Framework中不可或缺的那些技术。
其中最重要的非控制反转(IoC)容器莫属。在介绍完IoC容器之后,紧接着就全面介绍了面向切面编程(AOP)技术。Spring Framework有自己的AOP框架,它在概念上很容易理解,并且成功地解决了Java企业编程中80%的AOP需求。
关于Spring和AspectJ(当前来说,在功能方面,最丰富、最成熟的Java企业编程AOP实现)的集成,同样也会详细介绍。
1.IOC容器
本章介绍Spring的控制反转(IoC)容器。
1.1.Spring的IoC容器和Bean
本章介绍了控制反转(IoC)原理以及其Spring Framework实现。IoC也称为依赖注入(dependency injection,DI)。即通过构造函数参数、工厂方法的参数,或属性来定义对象的依赖关系(即它们需要使用的其他对象)。然后,容器在创建对象时注入这些依赖。这个过程从根本上反转(因此叫“控制反转”)了对象的对于其依赖的实例化过程。
org.springframework.beans
和org.springframework.context
的包是Spring Framework的IoC容器的基础包。BeanFactory
接口提供了能够管理任何类型对象的高级配置机制。ApplicationContext
是BeanFactory
的子接口。它增加了:
- 更容易与Spring的AOP特性集成
- 消息资源处理(用于国际化)
- 事件发布
- 应用层特定的上下文,如web应用中使用的
WebApplicationContext
简而言之,BeanFactory
提供了配置框架和基本功能,而ApplicationContext
添加了更多基于企业编程环境的功能。ApplicationContext
是BeanFactory
的一个完整超集,在本章描述Spring的IoC容器时指的都是ApplicationContext
。有关使用BeanFactory
而不是ApplicationContext
的更多信息,请参见BeanFactory
。
在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是由Spring IoC容器实例化、组装和管理的对象。否则,bean只是应用程序中的众多对象之一。bean及其之间的依赖关系反映在容器使用的配置元数据中。
1.2.容器概述
org.springframework.context.ApplicationContext
接口负责实例化、配置和组装bean,即可代表Spring IoC容器。容器通过读取配置元数据获得关于实例化、配置和组装哪些对象的指令。配置元数据用XML、Java注释或Java代码表示。它允许您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。
Spring提供了几个ApplicationContext
接口的实现。在独立的应用程序中,可以使用ClassPathXmlApplicationContext
或FileSystemXmlApplicationContext
。虽然XML是定义配置元数据的传统格式,但是您可以通过提供少量XML配置以声明方式指示容器支持使用Java注释或代码作为元数据格式。
在大多数应用程序场景中,不需要显式的用户代码来创建Spring IoC容器的一个或多个实例。例如,在web应用程序中,一个简单的8行(大约)样板web.xml文件通常就足够了(见Convenient ApplicationContext Instantiation for Web Applications)。如果您使用Spring Tools for Eclipse(一个强大的Eclipse开发环境),只需点击几下鼠标就可以轻松创建这个样板配置。
下图从较高层面展示了Spring是如何工作的。应用程序类与配置元数据相结合,这样在ApplicationContext
创建并初始化之后,您就拥有了一个配置完整且可执行的应用程序。
1.2.1.配置元数据
如上图所示,Spring IoC容器需要某种形式的配置元数据。此配置元数据代表了作为应用程序开发人员,您诉Spring容器如何实例化、配置和组装应用程序中的对象。
配置元数据传统上以一种简单而直观的XML格式提供,本章的大部分内容都使用这种格式来描述Spring IoC容器的关键概念和特性。
基于XML的元数据并不是唯一允许的配置元数据形式。Spring IoC容器本身与配置元数据的方式是完全解耦的。现在,许多开发人员为他们的Spring应用程序选择基于java的配置。
有关在Spring容器中使用其他形式的元数据的信息,请参见:
- Annotation-based configuration:Spring2.5引入了对基于注释的配置元数据的支持。
-
Java-based configuration:从Spring 3.0开始,Spring JavaConfig项目提供的许多特性成为了核心Spring框架的一部分。Starting with Spring 3.0, many features provided by the Spring JavaConfig project became part of the core Spring Framework. 因此,您可以通过使用Java而不是XML文件来定义应用程序类外部的bean。使用这些新特性,请参见
@Configuration
、@Bean
、@Import
和@DependsOn
注解。
Spring配置由至少一个(通常是多个)被容器管理的bean定义组成。基于XML的配置元数据通过root元素<beans/>中的<bean/>元素来配置。Java配置通常在@Configuration类中使用@Bean注解的方式来配置。
这些bean定义对应应用程序内的实际对象。比如:服务层对象(service)、数据访问层对象(DAO)、表示层对象(如Struts的Action
,SpringMVC的Controller
),还有一些底层基础设施对象(如Hibernate的SessionFactories
、JMS的Queues
)等等。通常,不需要在容器中配置细粒度的领域对象(POJO、JavaBean等),因为创建和加载领域对象通常是DAO和service的责任。但是,您可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象。参见Using AspectJ to dependency-inject domain objects with Spring。
下面的例子展示了基于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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- 这个bean的依赖和配置在这里 -->
</bean>
<bean id="..." class="...">
<!-- 这个bean的依赖和配置在这里 -->
</bean>
<!-- 更多的bean定义 -->
</beans>
- id属性是标识单个bean定义的字符串。
- class属性定义bean的类型并使用完全限定的类名。
id
属性的值指向对象。本例中没有关于依赖项的配置示例。更多信息请参见Dependencies。
1.2.2.实例化一个容器
在下面示例代码中,提供给ApplicationContext
构造函数的路径或路径列表是资源路径字符串,这些资源路径字符串允许容器从各种外部资源(如本地文件系统、Java CLASSPATH
等)加载配置元数据。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
在了解了Spring的IoC容器之后,您可能想了解更多关于Spring的
Resource
抽象(如参考资料所述),它为从URI语法中定义的路径读取InputStream提供了一种方便的机制。特别是,Resource
用于构建应用程序上下文,如Application Contexts and Resource Paths所述。
以下示例显示了服务层对象(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
https://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>
<!-- 更多的服务层bean定义在这里 -->
</beans>
下面的示例显示了数据访问对象(dao.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao"
class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- 这个bean的其他依赖和配置在这里 -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- 这个bean的其他依赖和配置在这里 -->
</bean>
<!-- 更多数据访问对象的bean定义在这里 -->
</beans>
在上面的例子中,服务层由PetStoreServiceImpl
类和JpaAccountDao
和JpaItemDao
类型的两个数据访问对象组成(基于JPA ORM)。namme
元素指的是JavaBean属性的名称,而ref
元素指的是另一个bean定义的名称。 id
和ref
元素之间的这种链接表示了对象之间的依赖关系。有关配置对象依赖关系的详细信息,请参见Dependencies。
组合基于XML的配置
将bean定义拆分成多个XML文件是很有用的。通常,每个单独的XML配置文件代表体系结构中的一个逻辑层或模块。
可以使用ApplicationContext
构造函数从所有这些XML文件加载bean定义。这个构造函数接受多个Resource
路径,如前一节所示。或者,使用<import/>
元素从另一个或多个文件加载bean定义。下面的例子展示了如何做到这一点:
<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
目录里。如您所见,前面的斜杠被忽略了。但是,考虑到这些路径是相对的,最好不要使用斜杠。导入的文件的内容(包括顶级<beans/>元素)必须是有效的基于Spring Schema的XML bean定义。
可以使用
.. /
来引用父目录中的文件,但不建议这样做。这样做将创建对当前应用程序之外的文件的依赖关系。特别是,不建议对classpath:
类型的URL(例如,classpath:../services.xml
)使用../
,因为运行解析过程会选择最近的
类路径根,然后查看其父目录。类路径的更改可能导致选择不同的、不正确的目录。
您可以始终使用完全限定的资源路径,而不是相对路径:例如,
file:C:/config/services.xml
或classpath:/config/services.xml
。但是,请注意,您这样会将应用程序的配置耦合到特定的绝对位置。通常,最好为这些绝对位置保留一个间接位置——例如,通过在运行时根据JVM系统属性解析的${…}
占位符。
命名空间本身提供了导入指令功能。除了普通bean定义之外,Spring提供的XML名称空间中还提供了更多的配置特性——例如,context
和util
名称空间。
网友评论