参考文档的这一部分涵盖了Spring框架绝对不可或缺的所有技术。

其中最重要的是Spring框架的控制反转 (IoC) 容器。在对Spring框架的IoC容器进行彻底处理之后,将全面覆盖Spring的面向方面编程 (AOP) 技术。Spring框架有自己的AOP框架,该框架在概念上易于理解,并成功解决了Java企业编程中AOP要求的80% 个最佳点。

还提供了Spring与AspectJ集成的覆盖范围 (目前在特征方面为richest - , 当然也是Java企业领域中最成熟的AOP实现)。

1. IoC 容器

本章介绍Spring的控制反转 (IoC) 容器。

1.1. Spring IoC容器和Bean简介

本章介绍了控制反转 (IoC) 原理的Spring框架实现。IoC也被称为依赖注入 (DI)。这是一个过程,其中对象仅通过构造函数参数、工厂方法的参数来定义其依赖项 (即,它们使用的其他对象),或从工厂方法构造或返回对象实例后在其上设置的属性。然后,容器在创建bean时注入这些依赖项。这个过程基本上是反转的 (因此得名,控制反转) bean本身通过使用类的直接构造或诸如服务定位器模式之类的机制来控制其依赖项的实例化或位置。

org.springframework.Beanorg.springframework.context 包是Spring Framework的IoC容器的基础。 BeanFactory 接口提供了一种高级配置机制,能够管理任何类型的对象。 ApplicationContextBeanFactory 的子接口。它补充:

  • 更容易与Spring的AOP功能集成
  • 消息资源处理 (用于国际化)
  • 事件出版
  • 应用程序层特定上下文,例如用于web应用程序的 WebApplicationContext

简而言之, BeanFactory 提供了配置框架和基本功能,并且 ApplicationContext 添加了更多企业特定功能。 ApplicationContextBeanFactory 的完整超集,仅在本章中用于Spring的IoC容器的描述中。有关使用 BeanFactory 而不是 ApplicationContext 的更多信息,请参阅 BeanFactory

在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是由Spring IoC容器实例化、组装和管理的对象。bean只是应用程序中众多对象之一。Bean及其之间的依赖关系反映在容器使用的配置元数据中。

1.2 容器概述

org.springframework.context.ApplicationContext 接口表示Spring IoC容器,负责实例化、配置和组装bean。容器通过读取配置元数据来获取有关要实例化、配置和组装哪些对象的指令。配置元数据以XML、Java注释或Java代码表示。它使您可以表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。

Spring提供了 ApplicationContext 接口的几个实现。在独立应用程序中,通常创建 ClassPathXmlApplicationContextFilesystemxmlapplicationcontext 的实例。虽然XML已成为定义配置元数据的传统格式,您可以通过提供少量XML配置来指示容器使用Java注释或代码作为元数据格式,以声明方式支持这些附加元数据格式。

在大多数应用场景中,不需要显式用户代码来实例化Spring IoC容器的一个或多个实例。例如,在web应用程序场景中,web中的简单的八行 (约八行) 样板web描述符XML。应用程序的xml文件通常就足够了 (请参阅Web应用程序的便捷ApplicationContext实例化)。如果使用Spring Tools for Eclipse (由Eclipse驱动的开发环境),则只需单击几下鼠标或击键即可轻松创建此样板配置。

下图显示了Spring如何工作的高级视图。您的应用程序类与配置元数据相结合,以便在创建和初始化ApplicationContext之后,您拥有一个完全配置的可执行系统或应用程序。
Spring 核心技术 - 图1
图1:The Spring IoC container

1.2.1 配置元数据

如上图所示,Spring IoC容器使用一种配置元数据形式。此配置元数据表示作为应用程序开发人员,您如何告诉Spring容器实例化、配置和组装应用程序中的对象。
配置元数据传统上以简单直观的XML格式提供,这是本章大部分用于传达Spring IoC容器的关键概念和功能的内容。

基于XML的元数据不是配置元数据的唯一允许形式。Spring IoC容器本身与实际写入此配置元数据的格式完全分离。如今,许多开发人员为他们的Spring应用程序选择基于Java的配置。有关在Spring

容器中使用其他形式的元数据的信息,请参阅:

  • 基于注释的配置: Spring 2.5引入了对基于注释的配置元数据的支持。
  • 基于Java的配置: 从Spring 3.0开始,Spring JavaConfig项目提供的许多功能成为核心Spring框架的一部分。因此,您可以使用Java而不是XML文件来定义应用程序类外部的bean。要使用这些新功能,请参阅 @ Configuration、 @ Bean、 @ Import和 @ relison注释。


Spring配置由容器必须管理的至少一个 (通常不止一个) bean定义组成。基于XML的配置元数据将这些bean配置为顶级 元素中的 元素。Java配置通常在 @ configuration类中使用 @ Bean注释的方法。

这些bean定义对应于组成应用程序的实际对象。通常,您可以定义服务层对象、数据访问对象 (DAOs) 、演示对象 (如支柱操作实例) 、基础结构对象 (如休眠会话工厂) 、JMS队列等。通常,不会在容器中配置细粒度的域对象,因为创建和加载域对象通常是DAOs和业务逻辑的责任。但是,您可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象。请参阅使用AspectJ依赖关系-使用Spring注入域对象。
以下示例显示了基于XML的配置元数据的基本结构:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="..." class="...">
  7. <!-- collaborators and configuration for this bean go here -->
  8. </bean>
  9. <bean id="..." class="...">
  10. <!-- collaborators and configuration for this bean go here -->
  11. </bean>
  12. <!-- more bean definitions go here -->
  13. </beans>
  • id属性是标识各个bean定义的字符串。
  • class属性定义bean的类型,并使用完全限定的classname。


id属性的值是指协作对象。此示例中未显示用于引用协作对象的XML。有关更多信息,请参阅依赖项。

1.2.2 实例化容器

提供给 ApplicationContext 构造函数的一个或多个位置路径是资源字符串,允许容器从各种外部资源 (例如本地文件系统、Java类路径、等等。)

  1. ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

在了解了Spring的IoC容器之后,您可能想进一步了解Spring的资源抽象 (如Resources中所述),它提供了一种方便的机制,用于从URI语法中定义的位置读取InputStream。特别是,资源路径用于构造应用程序上下文,如应用程序上下文和资源路径中所述。


以下示例显示服务层对象 (services.xml) 配置文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- services -->
  7. <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
  8. <property name="accountDao" ref="accountDao"/>
  9. <property name="itemDao" ref="itemDao"/>
  10. <!-- additional collaborators and configuration for this bean go here -->
  11. </bean>
  12. <!-- more bean definitions for services go here -->
  13. </beans>


以下示例显示了数据访问对象daos.xml文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="accountDao"
  7. class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
  8. <!-- additional collaborators and configuration for this bean go here -->
  9. </bean>
  10. <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
  11. <!-- additional collaborators and configuration for this bean go here -->
  12. </bean>
  13. <!-- more bean definitions for data access objects go here -->
  14. </beans>


在前面的示例中,服务层由PetStoreServiceImpl类和两个类型为JpaAccountDao和JpaItemDao的数据访问对象 (基于JPA对象关系映射标准) 组成。属性名称元素是指JavaBean属性的名称,而ref元素是指另一个bean定义的名称。id和ref元素之间的这种链接表达了协作对象之间的依赖关系。有关配置对象的依赖项的详细信息,请参阅依赖项。

组合基于XML的配置元数据

使bean定义跨越多个XML文件可能很有用。通常,每个单独的XML配置文件代表体系结构中的逻辑层或模块。
您可以使用应用程序上下文构造函数从所有这些XML片段加载bean定义。此构造函数采用多个资源位置,如上一节所示。或者,使用一次或多次出现的 元素从另一个或多个文件加载bean定义。以下示例显示如何执行此操作:

  1. <beans>
  2. <import resource="services.xml"/>
  3. <import resource="resources/messageSource.xml"/>
  4. <import resource="/resources/themeSource.xml"/>
  5. <bean id="bean1" class="..."/>
  6. <bean id="bean2" class="..."/>
  7. </beans>


在前面的示例中,从三个文件加载了外部bean定义: services.xml、messagessource.xml和themessource.xml。所有位置路径都相对于执行导入的定义文件so服务。xml必须与执行导入的文件位于同一目录或类路径位置,而消息源。xml和资源。xml必须位于导入文件位置下方的资源位置。如您所见,前导斜杠被忽略。然而,考虑到这些路径是相对的,最好不要使用斜杠。根据Spring Schema,正在导入的文件 (包括顶层 元素) 的内容必须是有效的XML bean定义。

可以但不建议使用相对 “//” 路径引用父目录中的文件。这样做会创建对当前应用程序之外的文件的依赖关系。特别是,不建议将此引用用于classpath: url (例如,classpath://services。xml),其中运行时解析过程选择 “最近的” 类路径根目录,然后查看其父目录。类路径配置更改可能会导致选择不同的、不正确的目录。 您始终可以使用完全限定的资源位置,而不是相对路径: 例如,文件: C:/config/services.xml或类路径:/config/services.xml。但是,请注意,您正在将应用程序的配置耦合到特定的绝对位置。通常,最好通过在运行时针对JVM系统属性解析的 “$ {…}” 占位符来保持这种绝对位置的间接。

命名空间本身提供导入指令功能。除普通bean定义之外的其他配置功能可在Spring - 提供的XML命名空间中找到,例如,上下文和util命名空间。

Groovy Bean定义DSL

作为外部化配置元数据的另一个示例,bean定义也可以在Spring的Groovy Bean定义DSL中表达,如从grail框架中得知的那样。通常,这种配置存在于 “.groovy” 文件中,其结构如以下示例所示:

  1. beans {
  2. dataSource(BasicDataSource) {
  3. driverClassName = "org.hsqldb.jdbcDriver"
  4. url = "jdbc:hsqldb:mem:grailsDB"
  5. username = "sa"
  6. password = ""
  7. settings = [mynew:"setting"]
  8. }
  9. sessionFactory(SessionFactory) {
  10. dataSource = dataSource
  11. }
  12. myService(MyService) {
  13. nestedBean = { AnotherBean bean ->
  14. dataSource = dataSource
  15. }
  16. }
  17. }

这种配置样式在很大程度上等同于XML bean定义,甚至支持Spring的XML配置命名空间。它还允许通过importbean指令导入XML bean定义文件。

1.2.3 使用容器

ApplicationContext是高级工厂的接口,能够维护不同bean及其依赖项的注册表。通过使用方法T getBean (字符串名称,类 必需类型),您可以检索bean的实例。
ApplicationContext允许您读取bean定义并访问它们,如以下示例所示:

  1. // create and configure beans
  2. ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
  3. // retrieve configured instance
  4. PetStoreService service = context.getBean("petStore", PetStoreService.class);
  5. // use configured instance
  6. List<String> userList = service.getUsernameList();

使用Groovy配置,引导看起来非常相似。它有一个不同的上下文实现类,它支持Groovy (但也理解XML bean定义)。以下示例显示Groovy配置:

  1. ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");

最灵活的变体是GenericApplicationContext与reader deleg - 结合使用,例如,与XML文件的xmlbeandefintionreader结合使用,如以下示例所示:

  1. GenericApplicationContext context = new GenericApplicationContext();
  2. new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
  3. context.refresh();

您还可以将Groovy ybeandefintionreader用于Groovy文件,如以下示例所示:

  1. GenericApplicationContext context = new GenericApplicationContext();
  2. new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
  3. context.refresh();

您可以在相同的ApplicationContext上混合和匹配此类reader委托,从不同的配置源中读取bean定义。
然后,您可以使用getBean检索bean的实例。ApplicationContext接口有一些其他的检索bean的方法,但是,理想情况下,您的应用程序代码不应该使用它们。实际上,您的应用程序代码应该根本没有对getBean() 方法的调用,因此根本不依赖于Spring api。例如,Spring与web框架的集成为各种web框架组件 (如控制器和hog管理的bean) 提供了依赖注入,允许您通过元数据 (例如自动加载注释) 声明对特定bean的依赖关系。