Spring 中文翻译
Spring IoC 容器
1.1 IoC Container 和 Bean 介绍
控制反转(Inversion of Control,IoC )也被称为依赖注入(Dependency Injection,DI)。这是一个,多个对象仅仅通过构造器参数,工厂方法参数,或者对象实例在被构造器初始化或者被工厂方法创建返回之后设置属性来定义它们之间的依赖关系(对象之间的调用关系)的过程。容器在它创建 bean 之后,注入之间的依赖项。这个过程 和 bean 本身通过使用类的直接构造器或服务定位机制,来控制其依赖项的实例化或位置,基本上是相反的(因此被称为控制反转)。
由人为的 new 新建对象,自行控制对象的实例和调用关系,转为容器控制。控制方发生改变所以是控制反转
org.springframework.beans 和 org.springframework.context 是 Spring IoC 容器的基础
BeanFactory 接口,提供了管理任何类型对象的高级配置机制
ApplicationContext 是 BeanFactory 的一个子接口。补充
- 更简单与 Spring 的 AOP 特性集成
- 信息资源处理(用于国际化)
- 事件发布
- 应用层特定的上下文。(例如
WebApplicationContext在 Web 应用程序中的使用)
简单的说,BeanFacotry 提供了配置框架和基础功能。ApplicationContext 增加了更多的企业特定的功能。ApplicationContext 是 BeanFactory 的一个完整的超集。
在 Spring 中,构成应用程序主干并且被 Spring IoC 容器所管理的,被称为 beans。一个 bean 是被 Spring IoC 容器实例化,组装和管理的一个对象。不然,bean 仅仅只是你应用程序中众多对象中的一个。Beans,之间的依赖关系由容器使用的配置元素据所体现。
1.2 容器概述
org.springframework.context.ApplicationContext接口代表了 Spring IOC 容器,负责实例化,配置和组装 beans。容器通过读取配置元素获取,该如何实例化,配置,组装。配置元数据以 XML 文档,java 注解,java 代码表示。它可以让你表示,组成应用的各个对象之间丰富的依赖关系。
Spring 提供了多个 ApplicationContext 接口的实现。在独立应用中,通常创建一个 ClasPathXmolApplicationContext 或 FileSystemXmlApplicationContext 实例。虽然 XML 一直是定义配置元数据的传统格式,但您可以通过提供少量 XML 配置来声明性地启用对这些附加元数据格式的支持,从而指示容器使用 Java 注释或代码作为元数据格式。
在大多数应用场景中,不需要显式的用户代码来实例化一个或多个 Spring IoC 容器实例(通过 xml 文件配置来实现)。
下图显示了 Spring 如何工作的高级视图。您的应用程序类与配置元数据相结合,因此,在ApplicationContext创建和初始化之后,您就有了一个完全配置且可执行的系统或应用程序。

1.2.1 配置元数据
如上图所示,Spring IoC 容器使用一种形式的配置元数据。此配置元数据表示你作为应用程序开发人员如何告诉 Spring 容器在你的应用程序中实例化、配置和组装对象。
配置元数据传统上以简单直观的 XML 格式提供。
- XML 配置
- 基于注解的配置
- 基于 Java 的配置
Spring 配置包含至少一个并且通常不止一个容器必须管理的 bean 定义。
基于 XML 的配置元数据将这些 bean 配置在<bean/><beans/>。
Java 配置通常在,@Configuration类中使用@Bean注解方法
这些 bean 定义对应于构成应用程序的实际对象。通常,你定义 service 层对象,数据访问对象(DAOs),持久化对象(Struts Action 实例),基础设施对象(Hibernate SessionFactories,JMS Queues 等)。通常,不会再容器中配置细粒度的域对象,因为创建和加载域对象通常是 DAO 和业务逻辑的责任。但是,您可以使用 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">
<!-- 该id属性是一个字符串,用于标识单个 bean 定义
该class属性定义 bean 的类型,并使用完全限定的类名。 -->
<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>
1.2.2 实例化一个容器
提供给ApplicationContext构造函数的一个或多个位置路径是资源字符串,它允许容器从各种外部资源(例如本地文件系统、JavaCLASSPATH 等)加载配置元数据。
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),(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类和两个数据访问对象组成:JpaAccountDao和JpaItemDao(基于JPA Object-Relational Mapping 标准)。该property name元素是指JavaBean属性的名称,以及ref元素指的是另一个bean定义的名称。id和ref元素之间的这种联系表达了协作对象之间的依赖关系。
编写基于 xml 的配置元数据
使 bean 定义跨越多个 XML 文件会很有用。通常,每个单独的 XML 配置文件都代表您架构中的一个逻辑层或模块。
您可以使用应用程序上下文构造函数从所有这些 XML 片段加载 bean 定义。该构造函数采用多个Resource位置 。或者,使用一个或多个<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,被导入文件的内容,包括顶级<beans/>元素,必须是有效的 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();
最灵活的变体是GenericApplicationContext结合读取器的委托——例如,结合XmlBeanDefinitionReaderfor XML 文件,如下例所示:
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
可以在同一个 ApplicationContext 上混合和匹配此类读取器的委托,从不同的配置源读取 bean 定义。
您可以使用getBean来获取 bean 的实例,ApplicationContext 接口还有一些其他方法来检索 bean,但是,理想情况下,您的应用程序代码永远不应该使用它们。实际上,您的应用程序代码根本不应该调用该 getBean()方法,因此完全不依赖于 Spring API。例如,Spring 与 Web 框架的集成为各种 Web 框架组件(例如控制器和 JSF 管理的 bean)提供了依赖注入,让您可以通过元数据(例如自动装配注解)声明对特定 bean 的依赖。
1.3 Bean 概述
Spring IoC 容器管理一个或多个 bean。这些 bean 是根据您提供给容器的配置元数据创建的(例如,以 XML<bean/>定义的形式 )。
在容器本身内,这些 bean 定义表示为BeanDefinition 对象,其中包含(除其他信息外)以下元数据:
- 一个包限定类名:通常是被定义的 bean 的实际实现类。
- Bean 行为配置元素,它说明 Bean 在容器中的行为方式(范围、生命周期回调等)
- 对 bean 执行其工作所需的其他 bean 的引用。这些引用也称为协作者或依赖项。
- 在新创建的对象中设置的其他配置设置——例如,管理连接池的 bean 中使用的连接数或连接池的大小限制。
| Property | 解释 |
|---|---|
| Class | Bean 的实际实现类 |
| Name | Bean 的命名 |
| Scope | Bean 作用域 |
| Constructor arguments | |
| Properties | |
| Autowiring mode | |
| Lazy initialization mode | |
| Initialization method | |
| Destruction |
bean 定义除了包含有关如何创建特定 bean 的信息之外,ApplicationContext实现还允许在容器外(由用户)创建的现有对象注册。这是访问 ApplicationContext 的 BeanFactory 通过使用getBeanFactory()方法,返回 BeanFactory DefaultListableBeanFactory实现来完成的。DefaultListableBeanFactory 通过registerSingleton(..)和 registerBeanDefinition(..)方法支持此注册。但是,典型的应用程序仅使用通过常规 bean 定义元数据定义的 bean。
1.3.1 Beans 命名
每个 bean 都有一个或多个标识符。这些标识符在管理 bean 的容器中必须是唯一的。一个 bean 通常只有一个标识符。但是,如果它需要多个,则可以将多余的视为别名。
在基于 XML 的配置元数据中,您可以使用id属性、name属性或两者来指定 bean 标识符。该id属性允许您指定一个 id。通常,这些名称是字母数字('myBean'、'someService' 等),但它们也可以包含特殊字符。如果要为 bean 引入其他别名,也可以在name 属性中指定它们,用逗号 ( ,)、分号 ( ;) 或空格分隔。
您不需要为 bean 提供 一个 name或一个 id。如果您未明确提供一个 name或id,则容器会为该 bean 生成一个唯一名称。但是,如果您想通过名称引用该 bean,通过使用ref元素或服务定位器样式查找,您必须提供名称。不提供名称的动机与使用内部 bean和自动装配协作者有关
在 Bean 定义之外给 Bean 取别名
在 bean 定义本身中,您可以通过使用最多一个由id属性指定的名称和在 name 属性中任意数量的其他名称的组合,为 bean 提供多个名称。这些名称可以是同一个 bean 的等效别名,并且在某些情况下很有用,例如让应用程序中的每个组件通过使用该组件本身特定的 bean 名称来引用公共依赖项。
然而,在定义 bean 的地方指定所有别名并不总是足够的。有时需要为在别处定义的 bean 引入别名。这在大型系统中很常见,其中配置在每个子系统之间拆分,每个子系统都有自己的一组对象定义。在基于 XML 的配置元数据中,您可以使用<alias/>元素来完成此操作
<alias name="fromName" alias="toName"/>
在这种情况下,命名的 bean(在同一容器中)fromName也可以在使用此别名定义后称为toName.
例如,子系统 A 的配置元数据可能引用名为subsystemA-dataSource的数据源。子系统 B 的配置元数据可能引用名为subsystemB-dataSource 的数据源。当主应用程序,组合使用这两个子系统时,主应用程序通过myApp-dataSource引用 DataSource 。要让所有三个名称都引用同一个对象,您可以将以下别名定义添加到配置元数据中:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
1.3.2 Beans 实例化
bean 定义本质上是创建一个或多个对象的方法。容器在询问时查看命名 bean 的方法,并使用该 bean 定义封装的配置元数据来创建(或获取)实际对象。
如果您使用基于 XML 的配置元数据,在<bean/>元素的class属性中指定要实例化的对象的类型(或类)。这个 class属性(在内部,它是BeanDefinition 实例的一个Class属性)通常是强制性的。您可以通过以下Class两种方式之一使用该属性:
- 通常,在容器本身通过反射调用其构造函数直接创建 bean 的情况下,指定要构造的 bean 类,有点等同于带有
new运算符的Java 代码 - 调用指定的实际类(包含
static的工厂方法)来以创建对象。在不太常见的情况下,容器调用类上的static工厂方法来创建 bean。调用static工厂方法返回的对象类型可能是同一个类,也可能完全是另一个类。
使用构造函数初始化
当您通过构造函数方法创建 bean 时,所有普通类都可以被 Spring 使用并与之兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 bean 类就足够了。但是,根据您对该特定 bean 使用的 IoC 类型,您可能需要一个默认(空)构造函数。
Spring IoC 容器几乎可以管理您希望它管理的任何类,大多数 Spring 用户更喜欢实际的 JavaBeans,它只有一个默认的(无参数)构造函数和适当的 setter 和 getter(以容器中的属性为模型)。
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
使用静态工厂方法实例化
在定义使用静态工厂方法创建的 bean 时,使用class 属性来指定包含static工厂方法的类和一个命名为factory-method的属性(指定工厂方法本身名称)。您应该能够调用此方法(带有可选参数,如下所述)并返回一个存活对象,该对象随后被视为通过构造函数创建。这种 bean 定义的一种用途是在遗留代码中调用static工厂。
以下 bean 定义指定通过调用工厂方法来创建 bean。定义中没有指定返回对象的类型(类),只指定包含工厂方法的类。在这个例子中,createInstance() 方法必须是静态方法。以下示例显示了如何指定工厂方法:
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
使用实例工厂方法实例化
与通过静态工厂方法实例化类似,使用实例工厂方法实例化从容器中调用一个现有的 bean 的非静态方法来创建新 bean。要使用此机制,请将class属性留空,并在factory-bean属性中指定当前(或父或祖先)容器中 bean 的名称,该容器包含要调用以创建对象的实例方法。使用factory-method属性设置工厂方法本身的名称。
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
一个工厂类也可以包含多个工厂方法
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
确定 Bean 的运行时类型
确定特定 bean 的运行时类型并非易事。bean 元数据定义中的指定类只是一个初始类引用,可能与声明的工厂方法结合,或者是FactoryBean 类可能导致 bean 的不同运行时类型,或者在实例工厂方法(通过指定factory-bean名称解析)的情况下根本没有被设置。此外,AOP 代理可能会使用基于接口的代理包装 bean 实例,并限制暴露目标 bean 的实际类型(仅其实现的接口)。
找出特定 bean 的实际运行时类型的推荐方法是BeanFactory.getType调用指定的 bean 名称。这将所有上述情况都考虑在内,并返回BeanFactory.getBean调用将针对相同 bean 名称返回的对象类型。
1.4 依赖关系
典型的企业应用程序不包含单个对象。即使是最简单的应用程序也有多个对象,它们协同工作以呈现最终用户所看到的连贯应用程序。
1.4.1 依赖注入
依赖注入 (DI) 是一个过程,对象仅仅通过构造器参数,工厂方法参数,或者对象实例在被构造器初始化或者被工厂方法创建返回之后设置属性来定义它们之间的依赖关系(对象之间的调用关系)的过程。容器在它创建 bean 之后,注入之间的依赖项。这个过程 和 bean 本身通过使用类的直接构造器或服务定位机制,来控制其依赖项的实例化或位置,基本上是相反的(因此被称为控制反转)。
DI 存在两种主要的变体:基于构造函数的依赖注入和基于 Setter 的依赖注入
基于构造函数的依赖注入
基于构造函数的 DI 是通过容器调用具有多个参数的构造函数来完成的,每个参数代表一个依赖项。调用带有特定参数的static工厂方法来构造 bean 几乎是等效的。
只能使用构造函数进行依赖注入的类
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private final MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
构造函数参数解析
构造函数通过使用参数的类型,进行参数解析匹配。那么在 bean 定义中定义构造函数参数的顺序就是在实例化 bean 时将这些参数提供给适当的构造函数的顺序。
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
使用基本类型时
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private final int years;
// The Answer to Life, the Universe, and Everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
构造函数参数类型匹配
过type属性显式指定构造函数参数的类型
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
构造函数参数索引
使用该index属性显式指定构造函数参数的索引(索引从 0 开始)
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
构造函数参数名称
可以使用构造函数参数名称进行值的消歧
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
基于 Setter 的依赖注入
基于 Setter 的 DI 是通过容器在调用无参数构造函数或无参数static工厂方法来实例化bean 后调用 bean 上的 setter 方法来完成的。
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
由于您可以混合使用基于构造函数和基于 setter 的 DI,因此根据经验,对强制依赖项使用构造函数,对可选依赖项使用 setter 方法或配置方法是一个很好的经验法则。
Spring 团队通常提倡构造函数注入,因为它可以让您将应用程序组件实现为不可变对象,并确保所需的依赖项不是null.
依赖解析过程
容器执行bean依赖解析如下:
ApplicationContext根据配置元数据中描述的所有 Bean,进行创建和初始化。- 每个 bean 的依赖关系以 properties、构造函数参数或静态工厂方法的参数(如果您使用它而不是普通构造函数)的形式表示。在实际创建 bean 时,将这些依赖关系提供给 bean。
- 每个属性或构造函数参数都是要设置的值的实际定义,或者是对容器中另一个 bean 的引用
- 值的每个属性或构造函数参数都从其指定格式转换为该属性或构造函数参数的实际类型,默认情况下,Spring 可以将以字符串格式提供的值转换为所有内置类型,例如
int、long、String、boolean等。
Spring 容器在创建容器时验证每个 bean 的配置。但是,在实际创建 bean 之前不会设置 bean 属性本身。创建容器时会创建单例范围并设置为预实例化(默认)的 Bean。。范围在 Bean Scopes 中定义。否则,仅在请求时才创建 bean。创建 bean 可能会导致创建 bean 图,因为 bean 的依赖项及其依赖项的依赖项(等等)被创建和分配。请注意,这些依赖项之间的解析不匹配可能会出现较晚 — 即,在第一次创建受影响的 bean 时。
循环依赖
如果您主要使用构造函数注入,则可能会创建无法解决的循环依赖场景。
例如:A类通过构造函数注入需要B类的实例,B类通过构造函数注入需要A类的实例。如果您将类 A 和 B 的 bean 配置为相互注入,则 Spring IoC 容器在运行时检测到此循环引用,并抛出一个 BeanCurrentlyInCreationException.
一种可能的解决方案是编辑一些类的源代码,以便由 setter 而不是构造函数来配置。或者,避免构造函数注入并仅使用 setter 注入。也就是说,虽然不推荐,但是可以通过setter注入来配置循环依赖。
与典型情况(没有循环依赖)不同,bean A 和 bean B 之间的循环依赖迫使其中一个 bean 在完全初始化之前注入另一个 bean(经典的鸡和蛋场景)。
您通常可以相信 Spring 会做正确的事情。它在容器加载时检测配置问题,例如对不存在的 bean 的引用和循环依赖。Spring 在真正创建 bean 时尽可能晚地设置属性并解析依赖项。这意味着,如果创建该对象或其依赖项时出现问题,则已正确加载的 Spring 容器稍后可以在您请求对象时生成异常——例如,由于缺少或无效,bean 会抛出异常。某些配置问题的这种潜在延迟可见性是为什么ApplicationContext默认情况下,实现预实例化单例 bean。以一些前期时间和内存为代价在实际需要之前创建这些 bean ,您ApplicationContext会在创建时发现配置问题,而不是稍后。您仍然可以覆盖此默认行为,以便单例 bean 延迟初始化,而不是急切地预实例化。
如果不存在循环依赖,当一个或多个协作 bean 被注入依赖 bean 时,每个协作 bean 在注入依赖 bean 之前都已完全配置。这意味着,如果 bean A 依赖 bean B,则 Spring IoC 容器在调用 bean A 上的 setter 方法之前完全配置 bean B。换句话说,bean 被实例化(如果它不是预实例化的单例) ),设置其依赖关系,并调用相关的生命周期方法(如配置的 init 方法 或 InitializingBean 回调方法)。
依赖解析的例子
基于 setter 的 DI
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
基于构造函数的 DI
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
不使用构造方法,使用一个 static 工厂方法
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
实例的工厂方法
// 仅仅修改 factory-bean
<bean id="exampleBean" factory-bean="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
public ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}

浙公网安备 33010602011771号