第三章 bean 的配置
? 在本章中,我们将介绍以下内容:
- bean 定义的继承:
- 如何解决 bean 类的构造函数的参数:
- 如何配置原始类型 (如 int 、float 等) 、集合类型(如 java.util.List、java.util.Map)等以及自定义类型 (如 Address ) 等的 bean 属性和构造函数参数;
- 如何通过使用 p 命名空间和 c 命名空间分别指定 bean 属性和构造参数来使用应用程序上下文 XML 文件变得简洁;
- Spring 的 FactoryBean 接口,运行编写自己的工厂类来创建 bean 实例;
- 模块化 bean 配置。
bean 定义的继承
? 我们在第一章和第二章中看到,应用程序上下文 XML 文件中的 bean 定义指定了 bean 类及其依赖项的完全限定名称。在某些场景下,为了使 bean 定义不那么冗长,你可能希望 bean 定义从另一个 bean 定义继承配置信息。下面介绍 MyBank 应用中这样的一个场景。
MyBank——bean 定义继承实例
? 在上一章中,我们了解到 MyBank 应用通过 DAO 来访问数据库。假设 MyBank 应用定义了一个可以与数据库交互的 DatabaseOperations 类,因此 MyBank 应用中的所有 DAO 都依赖于 DatabaseOperations 类来执行数据库操作,如下图所示。
? 上图展示了 FixedDepositDao 和 PersonalBankingDao 类依赖于 DatabaseOperations 类。以下应用程序上下文 XML 文件展示了这些类的 bean 定义。
<bean id="databaseOperations"
class="sample.spring.chapter01.bankapp.utils.DatabaseOperations"></bean>
<bean id="personalBankingDao" class="sample.spring.chapter01.bankapp.dao.PersonalBankingDaoImpl">
<property name="databaseOperations" ref="databaseOperations" />
</bean>
<bean id="fixedDepositDao" class="sample.spring.chapter01.bankapp.dao.FixedDepositDaoImpl">
<property name="databaseOperations" ref="databaseOperations" />
</bean>
? 上面 xml 中,personalBankingDao 和 fixedDepositDao bean 定义都使用 databaseOperations 属性来引用 DatabaseOperations 实例。这意味着 PersonalBankingDaoImpl 和 FixedDepositDaoImpl 类都定义了一个 setDatabaseOperations 方法,以允许 Spring 容器注入 DatabaseOperations 实例。
? 如果应用程序中的 多个 bean 共享一组公共的配置 (属性、构造函数参数等),则可以创建一个 bean 定义,作为其他 bean 定义的父定义。在 personalBankingDao 和 fixedDepositDao bean定义中,公共的配置是 databaseOperations 属性。下面展示了 personalBankingDao 和 fixedDepositDao bean 定义如何从父 bean 定义继承 databaseOperations 属性。
<bean id="databaseOperations" class="sample.spring.chapter03.bankapp.utils.DatabaseOperations"></bean>
<bean id="daoTemplate" abstract="true">
<property name="databaseOperations" ref="databaseOperations" />
</bean>
<bean id="fixedDepositDao" parent="daoTemplate" class="sample.spring.chapter03.bankapp.dao.FixedDepositDaoImpl">
</bean>
<bean id="personalBankingDao" parent="daoTemplate"
class="sample.spring.chapter03.bankapp.dao.PersonalBankingDaoImpl"></bean>
? 在上面的 xml 中,daoTemplate bean 定义了 fixedDepositDao 和 personalBankingDao bean 定义共享的公共配置。由于 fixedDepositDao 和 personalBankingDao bean 定义都需要 databaseOperations 依赖项,daoTemplate bean 定义使用 元素定义 databaseOperations 依赖项。 元素的 parent 属性指定从中继承配置的 bean 定义的名称。由于 fixedDepositDao 和 personalBankingDao bean 定义中的 parent 属性值为 daoTemplate ,因此他们从 daoTemplate bean 定义继承了 databaseOperation 属性。
? 如果 元素的 abstract 特性值设置为 true , 则表示 bean 定义是抽象的。在上面 xml 中, daoTemplate bean 定义是抽象的。请注意,Spring 容器不会尝试创建一个与抽象 bean 定义相对应的 bean 。
注意:
抽象 bean 不能作为其他 bean 定义的依赖项,也就是说,不能使用 <property> 或 <constructor-arg> 元素来引用抽象 bean 。
? 你可能已经注意到 daoTemplate bean 定义没有指定 class特性。如果父 bean 定义没有指定 class特性,则需要在子 bean 定义 (如 fixedDepositDao 和 personalBankingDao) 中指定 class 特性。注意,如果不指定 class 特性,则必须将 bean 定义为抽象的,以使 Spring 容器不会去尝试创建与之对应的 bean实例。
? 要验证 fixedDepositDao 和 personalBankingDao bean 定义是否继承了 daoTemplate bean 定义的 databaseOperations 属性。请执行下面的 java 代码。BankApp 类的 main 方法调用在 fixedDepositDao 和 personalBankingDao bean 中的方法,而这些 bean 调用 DatabaseOperations 实例上的方法。你会注意到,BankApp 的 main 方法成功运行。没有抛出任何异常。如果没有将 DatabaseOperations 实例注入 fixedDepositDao 和 personalBankingDao bean 中,那么代码将抛出 java.lang.NullPointerException。
package sample.spring.chapter03.bankapp;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import sample.spring.chapter03.bankapp.controller.FixedDepositController;
import sample.spring.chapter03.bankapp.controller.PersonalBankingController;
import sample.spring.chapter03.bankapp.domain.FixedDepositDetails;
public class BankApp {
private static Logger logger = Logger.getLogger(BankApp.class);
public static void main(String args[]) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
FixedDepositController fixedDepositController = context
.getBean(FixedDepositController.class);
fixedDepositController.submit(context
.getBean(FixedDepositDetails.class).setDepositAmount(100)
.setEmail("[email protected]").setId(1).setTenure(10));
logger.info("Your fixed deposit details : " + fixedDepositController.get());
PersonalBankingController personalBankingController = context
.getBean(PersonalBankingController.class);
logger.info(personalBankingController.getMiniStatement());
}
}
? 下图 显示了 fixedDepositDao 和 personalBankingDao bean 定义中,bean 定义继承是如何工作的
? 上图展示了 fixedDepositDao 和 personalBankingDao bean 定义从 daoTemplate bean 定义继承了 databaseOperations 属性(以 fixedDeopsitDa 和 personalBankingDao 标识的方框中的 property 属性)。上图还描述了 Spring 容器不会尝试创建 与 daoTemplate bean 定义相对应的bean 实例,因为他被标记为 abstract。
继承了什么
? 子 bean 定义从 父 bean 定义继承一下配置信息:
- 属性,通过 元素指定。
- 构造函数参数,通过 元素指定。
- 方法覆盖(见4,5节)
- 初始化和销毁方法(见 第五章);
- 工厂方法,通过 元素的 工厂方法特性指定(见2,3节,了解静态和实例工厂方法如何用于创建 bean)
原文地址:https://www.cnblogs.com/train99999/p/11964898.html