7.7.3 调用实例工厂方法创建Bean

7.7.3 调用实例工厂方法创建Bean

实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需使用工厂类即可,而调用实例工厂方法则需要工厂实例。所以配置实例工厂方法与配置静态工厂方法基本相似,只有一点区别:

  • 配置静态工厂方法使用class指定静态工厂类,
  • 而配置实例工厂方法则使用factory-bean指定工厂实例

使用实例工厂方法时,配置Bean实例的<bean>.元素无须class属性,因为Spring容器不再直接实例化该Bean, Spring容器仅仅调用实例工厂的工厂方法,工厂方法负责创建Bean实例。
采用实例工厂方法创建Bean<bean>元素时需要指定如下两个属性。

属性 描述
factory-bean 该属性的值为工厂Beanid
factory-method 该属性指定实例工厂的工厂方法。

与静态工厂方法相似,如果需要在调用实例工厂方法时传入参数,则使用<constructor-arg>元素指定参数值。

程序示例

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\instanceFactory
└─src\
├─beans.xml
├─lee\
│ └─SpringTest.java
└─org\
└─crazyit\
└─app\
├─factory\
│ └─PersonFactory.java
└─service\
├─impl\
│ ├─American.java
│ └─Chinese.java
└─Person.java

Person.java

下面先定义一个Person接口,实例工厂方法所产生的对象将实现Person接口

1
2
3
4
5
6
7
8
9
package org.crazyit.app.service;

public interface Person
{
// 定义一个打招呼的方法
public String sayHello(String name);
// 定义一个告别的方法
public String sayGoodBye(String name);
}

该接口定义了Person的规范,该接口必须拥有两个方法:能打招呼、能告别,实现该接口的类必须实现这两个方法。下面是Person接口的第一个实现类:American

American.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.crazyit.app.service.impl;

import org.crazyit.app.service.*;

public class American implements Person
{
// 实现Person接口必须实现如下两个方法
public String sayHello(String name)
{
return name + ",Hello!";
}
public String sayGoodBye(String name)
{
return name + ",Good Bye!";
}
}

Chinese.java

下面是Person接口的第二个实现类:Chinese:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.crazyit.app.service.impl;

import org.crazyit.app.service.*;

public class Chinese implements Person
{
// 实现Person接口必须实现如下两个方法
public String sayHello(String name)
{
return name + ",您好";
}
public String sayGoodBye(String name)
{
return name + ",下次再见";
}
}

PersonFactory是负责产生Person对象的实例工厂,该工厂类里提供了一个getPerson()方法,该方法根据传入的ethnic参数决定产生哪种Person对象。工厂类的代码如下。

PersonFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.crazyit.app.factory;

import org.crazyit.app.service.*;
import org.crazyit.app.service.impl.*;

public class PersonFactory
{
// 获得Person实例的实例工厂方法
// ethnic参数决定返回哪个Person实现类的实例
public Person getPerson(String ethnic)
{
if (ethnic.equalsIgnoreCase("chin"))
{
return new Chinese();
} else
{
return new American();
}
}
}

上面的PersonFactory就是一个简单的Person工厂, getPerson()方法就是负责生产Person的工厂方法。由于getPerson()方法没有使用static修饰,因此这只是一个实例工厂方法。
配置实例工厂创建Bean与配置静态工厂创建Bean基本相似,只需将原来的静态工厂类改为现在的工厂实例即可。该应用的配置文件如下。

beans.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置工厂Bean,该Bean负责产生其他Bean实例 -->
<bean id="personFactory" class="org.crazyit.app.factory.PersonFactory"/>
<!-- 下面配置驱动Spring调用personFactory这个Bean的getPerson()方法来创建Bean
该bean元素包含的constructor-arg元素用于为工厂方法指定参数,
因此这段配置会驱动Spring以反射方式来执行如下代码:
PersonFactory pf = container.get("personFactory"); // container代表Spring容器
chinese = pf.getPerson("chin"); -->
<bean id="chinese" factory-bean="personFactory"
factory-method="getPerson">
<!-- 配置实例工厂方法的参数 -->
<constructor-arg value="chin"/>
</bean>
<!-- 下面配置会驱动Spring以反射方式来执行如下代码:
PersonFactory pf = container.get("personFactory"); // container代表Spring容器
american = pf.getPerson("ame"); -->
<bean id="american" factory-bean="personFactory"
factory-method="getPerson">
<constructor-arg value="ame"/>
</bean>
</beans>

调用实例工厂方法创建Bean和调用静态工厂方法创建Bean的异同

调用实例工厂方法创建Bean,与调用静态工厂方法创建Bean的用法基本相似。区别如下。

  • 配置实例工厂方法创建Bean,必须将实例工厂配置成Bean实例;而配置静态工厂方法创建Bean,则无须配置工厂Bean
  • 配置实例工厂方法创建Bean,必须使用factory-bean属性确定工厂Bean;而配置静态工厂方法创建Bean,则使用class元素确定静态工厂类

相同之处如下:

  • 都需要使用factory-method属性指定产生Bean实例的工厂方法。
  • 工厂方法如果需要参数,都使用<constructor-arg>元素指定参数值。
  • 普通的设值注入,都使用<property>元素确定参数值。