Spring官方文档自翻(1.1 - 1.2)

145 阅读8分钟

1.IoC容器

1.1. 关于Spring IOC容器和Beans的介绍

这一章节主要包括控制反转原则在spring框架中的实现。IoC也被称为依赖注入。它是一个处理器,凭借它对象可以定义它的依赖(即和此对象一起工作的其他对象),它可以通过构造器参数,工厂方法的参数,或者是在对象实例化以后设置属性,或者是直接从一个工厂方法返回。然后容器就会在它创建这个bean的时候,把那些依赖也注入进去。这个过程从根本上来说是bean控制它的实例化和定位依赖的一种反转(这也是控制反转名词的由来), 通过使用类的直接构造,或者一种机制比如服务器定位模式。

org.springframework.beans和org.springframecontext这两个包是spring框架IoC容器的基础。BeanFactory接口提供了一种高级机制,它可以管理任意类型的对象。ApplicaionContext是BeanFactory的一个子接口。它添加了如下特性:

  1. 更容易和Spring的AOP特性整合
  2. 消息资源处理(用于国际化)
  3. 事件发布
  4. 应用层面的具体上下文,比如在web应用中使用的WebApplicationContext

简单来说,BeanFactory提供了配置框架和基本功能,而ApplicationContext添加了更多的企业级别的能力。ApplicationContext是BeanFactory的一个完整超集,在这一章中我们使用它来描述Spring ioc容器。

在sring中,构成你应用的主体和被spring ioc容器管理的对象就称做beans。一个bean就是一个被实例化和组装的对象,它被spring IOC容器所管理。另外,一个bean只是你应用中许许多多对象中的一个,Beans,以及他们的依赖一起,是被容器通过反射得到的,通过配置中的元数据。

1.2. 容器概览

org.springframework.context.ApplicationContext接口就代表了Spring IoC 容器,它负责实例化,配置和组装beans.容器通过读取配置信息元数据来获取哪些对象应该被实例化,配置和组装的信息。这些配置的元数据可以通过XML,Java注解,或者java代码的形式来表达。它可以让你表示哪些组成你应用的对象,以及这些对象之间的依赖相关性等。

Spring提供了ApplicationContext接口的几个实现类。在独立运行的应用中,通常会使用ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext实例。XML是传统的一种定义你配置元数据的方式,与此同时,你可以命令你的容器使用Java注解或者是代码的方式来作为元数据的格式,可以通过提供很小部分的xml注解来声明对这些补充的元数据格式的支持。

在大部分的应用场景中,用户是不需要自己写代码来实例化一个或者多个SpringIoc容器的。例如,在Web应用的场景中,简单的8行样板web描述的xml,在web.xml中,就可以大体满足了。如果你使用Spring Tools for Eclipse,你可以非常容易去创建这个样本配置,仅仅需要通过鼠标点击或者键盘敲击几下就可以了。

如下的图表在一个比较高阶抽象的层次展示了Spring是如何工作的。你的应用类是和你的配置元数据结合起来的,这样子的话,当你的ApplicationContext被创建和实例化以后,你就可以得到一个完全配置好的和可以执行的系统或者应用了。

1.2.1 配置元数据

在之前的图表中我们也展示了,Spring Ioc容器需要获得某种形式的配置元数据。这个配置元数据就表示了,你作为一个应用的开发人员,你告诉Spring容器如何去实例化,配置和组装你的应用中的对象。 配置元数据传统上来说,会提供使用简单的xml格式,这也是我们本章节大部分时候用来表述SpringIoC容器的关键概念和特性的方式。

有关其他在spring容器中使用的元数据格式,可见如下:

  1. 注解基础的配置:Spring2.5介绍了对注解配置元数据的支持。
  2. 基于java code的配置:从Spring3.0开始,许多由Spring JavaConfig项目提供的特性变成了Spring核心框架的一部分。因此,你可以通过java方式而不是xml的方式来定义你应用中的beans。要使用这些特性,可以去看@Configuraton,Bean,@Import和@DependsOn注解。

Spring配置通常包含至少一个或多个bean的定义。xml方式的元数据配置通过高层的中嵌套的内层来实现。java方式的配置通常使用@Bean注解在一个通过@Configuration注解的类的方法上面。

这些bean定义就和组成你应用的实际的对象相对应。通常,你会去定义service层的对象,dao层对象,表示层对象,例如Struts框架中的Action实例,基础设施的对象,比如Hibernate SessionFactories, JMS Queues等。通常,我们不需要去配置那些细粒度的domain对象,因为经常是那些daos和逻辑层业务来负责创建和加载domain对象的。然而,你可以使用Spring和AspectJ结合的方式来配置那些超出IoC容器控制范围以外的对象。以下是一个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属性的值就供合作的对象去引用。

1.2.2. 实例化容器

提供给ApplicationContext构造器的本地路径就是资源字符串,通过它容器来从许多外部的资源中来加载配置的元数据。比附本地的文件系统,java的CLASSPATH等等。

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

下面的例子展示了service层的对象配置文件(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>

在上面的例子中,service层包含了PetStoreServiceImpl类和两个数据访问对象,类型是JpaAccountDao和JpaItemDao(基于JPA ORM标准)。它的property name元素就与JavaBean的property的name相对应。ref 元素则指向了其他的bean定义的name。这种在id和ref元素之间的联系就表示了合作的对象之间的依赖。

组合xml方式的元数据配置 把bean的定义放到不同的XML文件中是有意义的。通常,一个独立的XML配置文件就代表了在你的架构中的一个逻辑层或者一个模块。 你可以使用使用应用上下文的构造器去从所有的xml碎片中加载bean的定义。这个构造器可以接受多个资源的路径,正如在上一个section所说的一样。作为一个备选,使用元素可以从其他的文件中去加载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。所有的路径对视相对于这个想要做import动作的定义文件来说的。所以,services.xml肯定是跟当前这个做import动作的文件在同一个目录或者classpath。同时,messageSource.xml和themeSource.xml肯定是在当前importing文件下的一个resource路径下。你可以看到themeSource.xml的路径中开头的反斜杠是被忽略了的。由于默认来说,我们都是使用相对的路径,所以最好根本就不要使用反斜杠开头。这个被import的文件的内容,包括顶层的元素,必须是合法的XML bean定义,根据Spring Schema的校验。

1.2.3 使用容器

ApplicationContext是一个可以维护不同的beans的注册表及他们之间依赖的高级工厂的接口。通过使用T getBean(String name, Class requiredType)方法,你可以获取你的beans的实例。 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,与读取器委托结合使用。例如,和XmlBeanDefinitionReader结合使用来读取XML文件,如下例子所示:

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方法来获取你的beans的实例。ApplicationContext接口还有一些其他的方法来获取bean,但是,理想情况下,你的应用代码永远不应该使用他们。实际上,你的应用代码完全不应该去调用getBean()方法,这样也不会与Spring的API有任何的依赖。例如,Spring和web的整合框架对不同的web框架组件提供了依赖注入,比如controllers和JSF管理的beans,让你可以在一个特定的bean上声明依赖(比如 autowiring 注解)。