Spring主要支持如下的三种方式来创建Bean。
1) 调用构造器创建Bean.
2) 调用静态工厂方法创建Bean
3) 调用实例工厂方法创建Bean
1.使用构造器创建Bean实例
如果采用构造注入,则要求配置文件为<bean…/>元素添加<constructor…/>子元素,每个<constructor…/>子元素配置一个构造器参数。Spring容器将使用带对应参数的构造器来创建Bean实例,Spring调用构造器传入的参数即可用于初始化Bean的实例,最后也将一个完整的Bean实例返回给程序。
2.使用静态工厂方法创建Bean
使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性不是指定Bean实例的实现类,而静态工厂类,Spring通过该属性知道由哪个工厂类创建Bean实例。<bean…./>元素需要指定如下两个属性:
1) class:该属性的值为静态工厂方法来生产Bean实例
2) factory-method:该属性指定静态工厂方法来生产Bean实例
下面定义一个Being接口,静态工厂方法所生产的产品是该接口的实例。
public interface Being
{
public void testBeing();
}
下面定义接口的两个实现类,静态工厂方法将会产生这两个实现类的实例。
Ø Cat.java
public class Cat implements Being
{
private String msg;
// msg的setter方法
public void setMsg(String msg)
{
this.msg = msg;
}
// 实现接口必须实现的testBeing方法
public void testBeing()
{
System.out.println(msg +
",猫喜欢吃老鼠");
}
}
Ø Dog.java
public class Dog implements Being
{
private String msg;
// msg的setter方法
public void setMsg(String msg)
{
this.msg = msg;
}
// 实现接口必须实现的testBeing()方法
public void testBeing()
{
System.out.println(msg +
",狗爱啃骨头");
}
}
下面的BeingFactory工厂包含了一个getBeing()静态方法,该静态方法用于返回一个Being实例,这就是典型的静态工厂。
public class BeingFactory
{
// 返回Being实例的静态工厂方法
// arg参数决定返回哪个Being类的实例
public static Being getBeing(String arg)
{
// 调用此静态方法的参数为dog,则返回Dog实例
if (arg.equalsIgnoreCase("dog"))
{
return new Dog();
}
// 否则返回Cat实例
else
{
return new Cat();
}
}
}
指定Spring让BeingFactory来生产Being对象,则应该按如下静态工厂方法的方式来配置Dog、Cat Bean。Spring配置文件如下。
<?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-4.0.xsd">
<!-- 下面配置驱动Spring调用BeingFactory的静态getBeing()方法来创建Bean
该bean元素包含的constructor-arg元素用于为静态工厂方法指定参数,
因此这段配置会驱动Spring以反射方式来执行如下代码:
dog = com.owen.app.factory.BeingFactory.getBeing("dog"); -->
<bean id="dog" class="com.owen.app.factory.BeingFactory"
factory-method="getBeing">
<!-- 配置静态工厂方法的参数 -->
<constructor-arg value="dog"/>
<!-- 驱动Spring以"我是狗"为参数来执行dog的setMsg()方法 -->
<property name="msg" value="我是狗"/>
</bean>
<!-- 下面配置会驱动Spring以反射方式来执行如下代码:
dog = com.owen.app.factory.BeingFactory.getBeing("cat"); -->
<bean id="cat" class="com.owen.app.factory.BeingFactory"
factory-method="getBeing">
<!-- 配置静态工厂方法的参数 -->
<constructor-arg value="cat"/>
<!-- 驱动Spring以"我是猫"为参数来执行dog的setMsg()方法 -->
<property name="msg" value="我是猫"/>
</bean>
</beans>
下面定个SpringTest.java用来测试。
public class SpringTest
{
public static void main(String[] args)
{
// 以类加载路径下的配置文件创建ClassPathResource实例
ApplicationContext ctx = new
ClassPathXmlApplicationContext("beans.xml");
Being b1 = ctx.getBean("dog" , Being.class);
b1.testBeing();
Being b2 = ctx.getBean("cat" , Being.class);
b2.testBeing();
}
}
通过静态工厂创建实例时需要对配置文件进行如下改变:
1) class属性的值不再是Bean实例的实现类,而是生成Bean实例的静态工厂类。
2) 使用factory-method属性指定创建Bean实例的静态工厂方法
3) 如果静态工厂方法需要参数,则使用<constructor-arg…/>元素指定静态工厂方法的参数。
3.调用实例工厂方法创建Bean
使用实例工厂方法时,配置Bean实例的<bean../>元素无须class属性,因为Spring容器不再直接实例化该Bean,Spring容器仅仅调用实例工厂的工厂方法,工厂方法负责创建Bean实例。采用实例工厂方法创建Bean的<bean…/>元素时需要指定如下两个属性:
1) factory-bean:该属性的值为工厂Bean的id
2) factory-method:该属性指定实例工厂的工厂方法
下面先定义一个Person接口,实例工厂方法所产生的对象将实例Person接口。
public interface Person
{
// 定义一个打招呼的方法
public String sayHello(String name);
// 定义一个告别的方法
public String sayGoodBye(String name);
}
下面是Person的第一个接口类:American.
public class American implements Person
{
// 实现Person接口必须实现如下两个方法
public String sayHello(String name)
{
return name + ",Hello!";
}
public String sayGoodBye(String name)
{
return name + ",Good Bye!";
}
}
下面是Person的第二个接口类Chinese
public class Chinese implements Person
{
// 实现Person接口必须实现如下两个方法
public String sayHello(String name)
{
return name + ",您好";
}
public String sayGoodBye(String name)
{
return name + ",下次再见";
}
}
下面定义个PersonFactory为Person的工厂类。 public class PersonFactory
{
// 获得Person实例的实例工厂方法
// ethnic参数决定返回哪个Person实现类的实例
public Person getPerson(String ethnic)
{
if (ethnic.equalsIgnoreCase("chin"))
{
return new Chinese();
}
else
{
return new American();
}
}
}
下面配置Spring的配置文件 bean.xml
<?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-4.0.xsd">
<!-- 配置工厂Bean,该Bean负责产生其他Bean实例 -->
<bean id="personFactory" class="com.owen.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>
下面写一个Test的类,用于测试。
public class SpringTest
{
public static void main(String[] args)
{
ApplicationContext ctx = new
ClassPathXmlApplicationContext("beans.xml");
Person p1 = ctx.getBean("chinese"
, Person.class);
System.out.println(p1.sayHello("Mary"));
System.out.println(p1.sayGoodBye("Mary"));
Person p2 = ctx.getBean("american"
, Person.class);
System.out.println(p2.sayHello("Jack"));
System.out.println(p2.sayGoodBye("Jack"));
}
}
4. 总结
调用实例工厂方法创建Bean,与调用静态工厂方法创建Bean的用法基本相似。区别如下 :
1) 配置实例工厂方法创建Bean,必须将实例工厂配置成Bean实例;而配置静态工厂方法创建Bean,则无须配置工厂Bean。
2) 配置实例工厂方法创建Bean,必须使用factory-bean属性确定工厂Bean;而配置静态工厂方法创建Bean,则使用class元素确定静态工厂类。
实例工厂方法创建与静态方法创建的相同地方如下:
1) 者需要使用factory-method属性指定生产Bean实例的工厂方法。
2) 工厂方法如果需要参数,都使用<constructor../>元素指定参数值
3) 普通的设置注入,都使用<property../>元素确定参数值