Spring 核心技术(1)

接上篇:Spring 框架概述html

version 5.1.8.RELEASEjava

这部分参考文档涵盖了 Spring Framework 全部绝对不可或缺的技术。web

其中最重要的是 Spring Framework 的控制反转(IoC)容器。在介绍完 Spring 框架的 IoC 容器以后,紧接着全面介绍 Spring 的面向切面编程(AOP)技术。Spring Framework 有本身的 AOP 框架,它在概念上易于理解,而且成功地定位了 Java 企业编程中 AOP 需求的 80% 最佳击球点。spring

Spring 提供与 AspectJ (目前功能最丰富,也是Java企业领域中最成熟的 AOP 实现)的集成。sql

1. IoC容器

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

1.1 Spring IoC 容器和 Bean 简介

本章介绍了 Spring Framework 控制反转(IoC)的实现原理。IoC 也称为依赖注入(DI)。经过这个机制,对象能够经过构造方法参数、工厂方法参数以及经过工厂方法构建或返回的实例上设置的属性来定义它们的依赖关系(即它们使用的其余对象)。而后容器在建立 bean 时注入这些依赖项。这个过程从根本上反转了 Bean 自身经过直接调用构造方法或服务定位模式等机制来控制实例化或定位其依赖的模式,所以叫作控制反转。api

org.springframework.beansorg.springframework.context 包是 Spring 框架的 IoC 容器的基础。BeanFactory 接口提供了一种可以管理任何类型对象的高级配置机制。ApplicationContext 是 BeanFactory 的子类。它补充的内容有:session

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

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

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

1.2 容器概览

org.springframework.context.ApplicationContext 接口表明 Spring IoC 容器,负责实例化、配置和组装 bean。容器经过读取配置元数据获取有关须要实例化、配置和组装对象的指令。配置元数据以 XML、Java 注解或 Java 代码表示,经过它能够表示构成应用的对象以及对象之间丰富的依赖关系。

Spring 提供了多种 ApplicationContext 接口实现。在传统单机应用中,一般会建立一个 ClassPathXmlApplicationContextFileSystemXmlApplicationContext 的实例。虽然 XML 是定义配置元数据的传统格式,但你也能够经过提供少许 XML 配置声明容器启用对其余元数据格式的支持后使用 Java 注解或代码做为元数据格式。

在大多数应用程序方案中,不须要显式使用代码来实例化 Spring IoC 容器实例。例如,在 Web 应用程序场景中,应用程序文件 web.xml 中一个 8 行左右的 web 描述模板 XML 就足够了(请参阅 Web 应用程序快速实例化 ApplicationContext)。若是你使用 Spring Tool Suite(一个基于 Eclipse 的开发环境),只需点击几下鼠标或按几下键盘便可轻松建立此模板配置。

下图是 Spring 工做原理的高级视图。应用程序类与配置元数据相结合,在 ApplicationContext 建立并初始化以后,便可拥有彻底配置且可执行的系统或应用程序。

images/container-magic.png

1.2.1 配置元数据

如上图所示,Spring IoC 容器使用一系列配置元数据。这些配置元数据描述了Spring 容器在应用程序中如何实例化,配置和组装对象。

传统配置元数据使用简单直观的 XML 格式,本章大部份内容也是用 XML 来表达 Spring IoC 容器的关键概念和功能。

XML 不是惟一的配置元数据格式。Spring IoC 容器与实际编写配置元数据的格式彻底解耦。目前,许多开发人员为其 Spring 应用程序选择基于 Java 的配置

有关在 Spring 容器中使用其余形式的元数据的信息,请参阅:

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

Spring 配置信息由至少一个(一般不止一个) 必须由容器进行管理的 bean 定义组成。基于 XML 的配置元数据将这些 bean 配置为顶级元素 <beans/> 内的 <bean/> 元素。基于 Java 的配置一般在使用 @Configuration 注解的类中使用带有 @Bean 注解的方法。

这些 bean 定义对应构成应用程序的实际对象。咱们通常会定义服务层对象,数据访问对象(DAO),展现层对象(例如 Struts Action 实例),基础结构对象(例如 Hibernate SessionFactories、JMS Queues 等)。通常不会在容器中配置细粒度的域对象,由于一般由 DAO 和业务逻辑负责建立和加载域对象。然而,你可使用 Spring 集成 AspectJ 来配置非 IoC 容器建立的对象。请参阅使用 Spring 和 AspectJ 进行域对象的依赖注入

如下示例显示了基于 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 属性的值表示协做对象。在此示例中未包含用于引用协做的对象的 XML。有关更多信息,请参阅依赖

1.2.2 实例化容器

提供给 ApplicationContext 构造函数的位置路径是一个资源字符串,它容许容器从各类外部资源加载配置元数据,例如本地文件系统、Java 环境变量等。

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

在了解了 Spring 的 IoC 容器以后,你可能想要了解有关 Spring 资源抽象化(参考资源描述)的更多信息,特别是 Resource 路径用于构建应用程序上下文(请参考应用程序上下文和资源路径),它提供了一种便捷的机制从 URI 语句中定义的位置读取 InputStream。。

如下示例展现了服务层对象配置文件(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>

如下示例展现了数据访问对象文件(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
        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 类和两个数据访问对象 JpaAccountDaoJpaItemDao(基于 JPA 对象关系映射标准)组成。property 元素的 name 属性指的是 JavaBean 属性的名称,ref 属性指向另外一个 bean 定义的名称。元素 idref 之间的这种联系表达了协做对象之间的依赖关系。有关配置对象的依赖关系的详细信息,请参阅依赖关系

编写基于XML的配置元数据

一般,每一个单独的 XML 配置文件都对应着架构中的逻辑层或模块,让 bean 定义在多个 XML 文件中生效会很是有用。

如上一节中所示,应用程序上下文构造函数可使用多个 Resource 位置,它能够从这些 XML 片断中加载 bean 定义。另外也可使用一个或多个 <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 目录中。正如你所见,前边的斜杠会被忽略掉。鉴于提供的都是相对路径,因此最好不要使用斜杠。这些文件中包括根据 Spring Schema 定义的正确的 XML Bean 在内的内容都会被导入,包括顶级元素 <beans/>

虽然可使用相对路径“../”引用父目录中的文件,但不建议这样使用,由于这样作会使得当前应用依赖程序以外的文件。很是不建议使用 classpath:URL(例如,classpath:../services.xml)引用文件,由于运行时解析过程会选择“最近”的环境变量根目录,而后查找其父目录。环境变量配置的更改可能致使目录选择不正确。

可使用完整的资源位置替代相对路径,例如,file:C:/config/services.xml 或 classpath:/config/services.xml。然而须要注意应用程序的配置将会与特定的绝对路径耦合。一般最好为这些绝对路径保持间接联系,例如经过在运行时经过“$ {...}”占位符替代 JVM 系统属性。

命名空间自己提供了导入指令的功能。Spring 提供的一系列 XML 命名空间中提供了除普通 bean 定义以外的其余配置功能,例如 context 和 util 命名空间。

Groovy Bean 定义 DSL

做为外化配置元数据的另外一个示例,bean 定义也能够在 Spring 的 Groovy Bean 定义 DSL 中表示,就像 Grails 框架。一般此类配置位于“.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 使用容器

ApplicationContext 是一个高级工厂接口,主要负责维护不一样 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 的上下文实现类(也支持 XML bean 定义)。如下示例展现了 Groovy 配置:

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

最灵活的使用方式是 GenericApplicationContext 与读取器委派结合使用,例如针对 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 框架组件(如控制器和 JSF 托管的 bean)提供依赖注入,以便经过元数据声明对特定 bean 的依赖关系,例如自动装配注解。

相关文章
相关标签/搜索