原文地址:docs.spring.io/spring-fram…
前言
文档的本部分涵盖了Spring框架中绝对不可或缺的所有技术。其中最重要的是Spring框架的控制反转(IoC)容器。在对Spring框架的IoC容器进行了全面的处理之后,紧接着全面介绍了Spring的面向方面编程(AOP)技术。Spring框架有自己的AOP框架,它在概念上很容易理解,并且成功地解决了Java企业编程中80%的AOP需求。还介绍了Spring与AspectJ的集成(就特性而言,目前AspectJ是最丰富的,当然也是Java企业中最成熟的AOP实现)。本节先介绍IoC容器。
1、IoC容器
本节介绍Spring的控制反转(IoC)容器
1.1、Spring IoC容器和bean的介绍
本章介绍Spring框架实现控制反转(IoC)的原理(IoC也称为依赖项注入DI)。在这过程中,对象只能通过构造函数、工厂方法的参数或sett方法来定义它们的依赖关系(即它们使用的其他对象),容器在创建bean时注入这些依赖项。这个过程基本上是bean直接调用new方法或诸如Service Locator模式这样的机制来控制其依赖项的实例化的逆过程(因此得名“控制反转”)。
org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基础包。BeanFactory接口提供了能够管理任何类型对象的高级配置机制。ApplicationContext是BeanFactory的一个子接口。它补充了:
-
更容易与Spring的AOP特性集成
-
消息资源处理(用于国际化)
-
事件发布
-
应用层特定的上下文,如web应用中使用的WebApplicationContext。
在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是由Spring IoC容器实例化、组装和管理的对象。换而言之,bean是应用程序中的众多对象之一。bean及其之间的依赖关系反映在容器使用的配置元数据中。
1.2 容器概述
org.springframework.context.ApplicationContext接口用来表示Spring IoC容器,负责实例化、配置和组装bean。配置元数据可以用XML、Java注释或Java代码表示,容器通过读取配置元数据获得关于实例化、配置和组装对象的指令。它允许您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。
Spring提供了ApplicationContext接口的几个实现。在独立应用程序中,通常会创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的实例。虽然XML是定义配置元数据的传统格式,但是您可以通过提供少量XML配置以声明方式支持这些额外的元数据格式,指示容器使用Java注释或代码作为元数据格式。
在大多数应用程序场景中,不需要显式的用户代码来实例化Spring IoC容器的一个或多个实例。例如,在一个web应用程序场景中,在应用程序的web. XML文件中简单的8行左右web描述符XML样本就足够了(参见web应用程序上下文实例化)。如果您使用用于Eclipse的Spring Tools (Eclipse支持的开发环境),那么只需点击几下鼠标或击几下键,就可以轻松创建这个样板配置。
下图显示了Spring如何工作的视图。应用程序类与配置元数据相结合,这样在ApplicationContext创建并初始化之后,您就拥有了一个配置完整且可执行的系统或应用程序。
1.2.1 配置元数据
如上图所示,Spring IoC容器使用一种配置元数据形式进行构建,此配置元数据表示应用程序开发人员,告诉Spring容器如何实例化、配置和组装应用程序中的对象。
配置元数据传统上以一种简单而直观的XML格式提供,本章的大部分内容都使用这种格式来传达Spring IoC容器的关键概念和特性。
基于xml的元数据并不是唯一允许的配置元数据形式。Spring IoC容器本身与配置元数据方式完全分离。现在,许多开发人员为他们的Spring应用程序选择基于java的配置。
有关在Spring容器中使用其他形式的元数据的信息,请参见:
-
基于注释的配置(docs.spring.io/spring-fram…):spring2.5引入了对基于注释的配置元数据的支持。
-
基于java注解的配置(docs.spring.io/spring-fram…):从Spring 3.0开始,Spring JavaConfig项目提供的许多特性成为了核心Spring框架的一部分。因此,您可以通过使用Java注解而不是XML文件来定义应用程序的bean。要使用这些新特性,请参阅@Configuration、@Bean、@Import和@DependsOn注释。
Spring配置由容器必须管理的bean定义组成:基于xml的配置元数据将这些bean配置为顶层元素中元素;Java注解配置通常使用@Configuration类中使用@ bean注释的方法。
这些bean定义对应于组成应用程序的实际对象。通常,您需要定义服务层对象、数据访问对象(dao)、控制层对象(如Struts Action实例)、基础设施对象(如Hibernate SessionFactories、JMS队列)等等。通常,不需要在容器中配置领域对象,因为创建和加载域对象通常是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="..." 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的类型,并使用完全限定 类名。
id的成员变量引用协作对象。引用协作对象的示例没有显示在这个例子中。有关更多信息,请参见Dependencies一节
1.2.2 容器的实例化
ApplicationContext构造函数接收字符串格式的资源路径,这些资源字符串允许容器从各种外部资源(如本地文件系统、Java CLASSPATH等)加载配置元数据。
ApplicationContext context = new ClassPathXmlApplicationContext("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
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"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</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">
<!-- 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(基于JPA对象关系映射标准)类型的两个数据访问对象组成。property name元素指明JavaBean属性的名称,ref元素引用另一个bean定义的名称。id和ref元素之间的这种链接表示了协作对象之间的依赖关系。有关配置对象依赖项的详细信息,见 Dependencies一节
编写基于xml的配置元数据
让bean定义跨越多个XML文件是很有用的。通常,每个单独的XML配置文件代表体系结构中的一个逻辑层或模块。如前一节所示,可以使用应用程序上下文构造函数从所有这些XML片段加载bean定义。此构造函数接受多个Resource位置;或者,使用一次或多次元素从另一个或多个文件加载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文件夹下。前面的斜杠会被忽略,但是,考虑到这些路径是相对的,最好不要使用斜杠。根据Spring Schema,导入的文件的内容(包括顶级元素)必须是有效的XML bean定义。
可以使用相对的".. /"来引用父目录中的文件,但不建议这样做。这样做将创建对当前应用程序之外的文件的依赖关系。特别是不建议对classpath: url(例如,classpath:../services.xml)使用此引用,运行时解析过程选择“最近的”类路径根,然后查看其父目录。类路径配置更改可能导致选择不同的、不正确的目录。
您可以始终使用完全限定的资源位置,而不是相对路径:例如,文件:C:/config/services.xml或类路径:/config/services.xml。但是,请注意,您是将应用程序的配置耦合到特定的绝对位置。通常,最好为这些绝对位置保留一个间接位置——例如,通过在运行时根据JVM系统属性解析的“${…}”占位符。
Groovy bean Definition
作为外部化配置元数据,bean定义也可以在Spring的Groovy bean Definition DSL中表示,Groovy文件的结构如下所示:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
这种配置风格很大程度上等同于XML bean定义,甚至支持Spring的XML配置名称空间。它还允许通过importBeans指令导入XML bean定义文件。
1.2.3 使用ioc容器
ApplicationContext是一个高级工厂的接口,该工厂能够维护不同bean及其依赖项。通过使用T getBean(String name, Class 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感知的(但也理解XML bean定义)。下面的例子展示了Groovy的配置:
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
最灵活的变体是GenericApplicationContext与reader结合使用——例如,XML文件使用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();
您可以在相同的ApplicationContext上混合和匹配这样的读取器委托,从不同的配置源读取bean定义。然后您可以使用getBean来检索bean的实例。ApplicationContext接口有一些其他的方法用于检索bean,但是,理想情况下,应用程序代码不应该使用它们。实际上,您的应用程序代码根本不应该调用getBean()方法,达到不依赖Spring api的目的。例如,Spring与web框架的集成为各种web框架组件提供了依赖注入(如controller和jsf的bean),允许您通过元数据(如自动装配注释)声明对特定bean的依赖。