spring文档阅读——Core: The IoC Container

用了这么久的spring框架却一直不知其所以然,直接在网上看别人的攻略又感觉差了点什么,因此决定系统的看一下spring官方的英文文档。本系列博客将按照每一篇文章对应官方文档中的一个小节的形式发布,文章内容分为正文和单词两部分。
笔者的英文水平一般,正文中的引用翻译也只是部分翻译,故本文只是spring文档阅读过程中的记录和分享,不可作为译文参考。
官方文档地址:https://spring.io/projects/spring-framework
欢迎转载,转载时注明原作者即可。


正文

本文所列部分对于spring框架而言都是核心技术,缺一不可。


Spring IoC容器

1. IoC和Bean简介

Foremost amongst these is the Spring Framework’s Inversion of Control (IoC) container.
IoC is also known as dependency injection (DI).

如果要在spring框架所有核心技术中挑出一个最重要的,那一定是IoC(控制反转)/DI(依赖注入)(是的,它们其实是同一个东西)。以下是关于IoC的定义:

It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean.
IoC指的是对象仅通过构造函数的参数工厂方法的参数、或者是被构造函数或工厂方法创建后返回的属性来定义自身依赖的过程。当容器创建bean时就会将那些已经被定义过的依赖注入进去。

IoC的两个关键包分别是org.springframework.beansorg.springframework.context

BeanFactory是提供框架配置和基本功能的接口,它的配置机制使得我们可以轻易的管理任何类型的对象。BeanFactory的子接口ApplicationContext则补充了一些企业开发相关的功能,ApplicationContext同时也是BeanFactory的超集。

在spring中,被IoC容器实例化、组装或以其他方式管理的对象称为bean。各种bean以及它们之间的依赖关系反映在spring容器配置的元数据中。

此处文档中还有一句Otherwise, a bean is simply one of many objects in your application.,我的理解是此处的bean指的是javabean,希望有大佬解惑


2. 容器概览

org.springframework.context.ApplicationContext接口代表着spring IoC容器,它负责通过读取元数据获取有关对象的配置说明并实例化、配置和组装bean配置元数据通常以xml注解java代码的形式表示,元数据中包含了组成应用程序的对象以及这些对象之间复杂的依赖关系。spring已经预设了一些ApplicationContext接口的实现,如ClassPathXmlApplicationContextFileSystemXmlApplicationContext等。下图展示了spring的工作原理视图:
spring文档阅读——Core: The IoC Container

2.1 配置元数据

开发者可以通过配置元数据告诉spring容器如何实例化、配置和组装对象,传统情况下(spring2.5以前)以xml格式表示(如果用springboot的话一般不需要写配置文件,而是通过在标注了@Configuration的类里添加带@Bean的方法),spring配置由容器必须管理的至少一个或多个bean定义组成。

Java configuration typically uses @Bean-annotated methods within a @Configuration class.

  • 从spring2.5开始,spring框架开始支持注解配置模式
  • 从spring3.0开始,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
        http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- 引入其他的xml文件 -->
    <import resource="xxx.xml"/>
    <import resource="resources/yyy.xml"/>
    <import resource="/resources/zzz.xml"/>

    <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>

2.2 实例化容器

ApplicationContext的构造函数可以从参数(一个或多个字符串)中获取到外部资源路径,然后再从这些外部资源中读取配置元数据,以下是通过ClassPathXmlApplicationContext构造ApplicationContext的例子:

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

除了xml外,也可以通过dsl(Groovy)定义bean。但是由于我没有在项目中实际使用过,所以在此不作举例。

2.3 容器的使用

ApplicationContext是一个高级接口,它维护着不同的beans及其依赖的注册表。通过方法

T getBean(String name, Class<T> requiredType)

可以获取到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();

我们不仅可以通过getBean()方法获取到bean实例,spring还提供了一些其他的方法达到相同的目的,但是我们基本上用不到这些方法。而且按照官方的说法,我们甚至连getBean()都不需要调用,业务逻辑不需要依赖spring的API。以web为例,推荐的做法是通过注解(@Service@Controller等)声明bean


3. Bean概览

spring IoC容器管理着许多通过配置元数据创建的bean

对于容器本身而言,bean定义被表示为BeanDefinition对象,它包含了以下元数据:

 - 包限定类名,指向bean的实际实现类;
 - bean在容器中的行为,包括作用域、生命周期回调等;
 - 使bean正常工作所需的其他bean的引用,即依赖;
 - 其他配置,如连接池的连接数限制或大小限制等。

以下是一个bean定义的例子:

<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>

3.1 Bean的命名规范

在spring容器中,每个bean至少有一个标识符,且每个标识符必须具有唯一性。一般情况下一个bean只会有一个标识符(使用id属性),如果需要多个标识符的话,额外的标识符被称为alias(别名)

在xml格式的配置元数据中, 可以使用id属性、name属性或两者来指定 bean 标识符,两者都允许使用字母、数字、某些特殊字符来精确描述bean的特征。

idname不是必填项,如果没有为bean指定idname,容器会自动为bean生成一个唯一的name。但是如果使用者需要通过ref元素name查找bean,则必须手动指定bean的name属性。

bean的命名遵循驼峰命名法:首字母小写,其后每一个单词的首字母大写。比如:password、userAccount、fatSuperMan等。bean的名称最好与其作用相关,方便阅读和理解。

关于aliases
在大型系统中,相同的bean在每个子系统都有不同的对象定义,这时我们可以使用alias来为bean定义别名:

<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>

在上面的例子中,对于同一个beanmyApp-dataSource,子系统A通过subsystemA-dataSource引用,子系统B通过subsystemB-dataSource引用。以上配置使得myApp-dataSourcesubsystemA-dataSourcesubsystemB-dataSource三个名称指向了同一个对象,并且不会与任何其它定义产生冲突。

3.2 实例化Bean

待续


单词

Inversion of Control	控制反转(IoC)
dependency injection	依赖注入(DI)
sub-interface			子接口
enterprise-specific		企业特定的
superset				超集
metadata				元数据
instantiate				实例化
annotation				注解
fine-grained			细粒度
alias					别名