1. 使用静态工厂方法创建Bean
使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类。因为Spring需要知道是用哪个工厂来创建Bean实例。另外,还需要使用factory-method来指定静态工厂方法名,Spring将调用静态工厂方法(可能包含一组参数),来返回一个Bean实例,一旦获得了指定Bean实例,Spring后面的处理步骤与采用普通方法创建Bean实例则完全一样。需要注意的是,当使用静态工厂方法来创建Bean时,这个factory-method必须要是静态的。这段阐述听上去有点晕,话不多说,上代码:
先定义一个接口,静态方法产生的将是该接口的实例:
1public interface Animal { 2 public void sayHello(); 3}
下面是接口的两个实现类:
1public class Cat implements Animal { 2 private String msg; 3 //依赖注入时必须的setter方法 4 public void setMsg(String msg){ 5 this.msg = msg; 6 } 7 @Override 8 public void sayHello(){ 9 System.out.println(msg + ",喵~喵~"); 10 } 11} 12 13public class Dog implements Animal { 14 private String msg; 15 //依赖注入时必须的setter方法 16 public void setMsg(String msg){ 17 this.msg = msg; 18 } 19 @Override 20 public void sayHello(){ 21 System.out.println(msg + ",旺~旺~"); 22 } 23}
下面的AnimalFactory工厂中包含了一个getAnimal的静态方法,该方法将根据传入的参数决定创建哪个对象。这是典型的静态工厂设计模式。
1public clas AnimalFactory { 2 public static Animal getAnimal(String type){ 3 if ("cat".equalsIgnoreCase(type)){ 4 return new Cat(); 5 } else { 6 return new Dog(); 7 } 8 } 9}
如果需要指定Spring使用AnimalFactory来产生Animal对象,则可在Spring配置文件中作如下配置:
1<!-- 配置AnimalFactory的getAnimal方法,使之产生Cat --> 2<bean id="cat" class="com.abc.AnimalFactory" factory-method="getAnimal"> 3 <!-- 配置静态工厂方法的参数,getAnimal方法将产生Cat类型的对象 --> 4 <constructor-arg value="cat" /> 5 <!-- 通过setter注入的普通属性 --> 6 <property name="msg" value="猫猫" /> 7</bean> 8<!-- 配置AnimalFactory的getAnimal方法,使之产生Dog --> 9<bean id="dog" class="com.abc.AnimalFactory" factory-method="getAnimal"> 10 <!-- 配置静态工厂方法的参数,getAnimal方法将产生Dog类型的对象 --> 11 <constructor-arg value="dog" /> 12 <!-- 通过setter注入的普通属性 --> 13 <property name="msg" value="狗狗" /> 14</bean>
从上面的配置可以看出:cat和dog两个Bean配置的class和factory-method完全相同,这是因为两个实例都使用同一个静态工厂类、同一个静态工厂方法产生得到的。只是为这个静态工厂方法指定的参数不同,使用<constructor-arg />元素来为静态工厂方法指定参数。
主程序获取cat和dog两个Bean实例的方法不变,同样只需要调用Spring容器的getBean()即可:
1public class Test { 2 public static void main(String args[]){ 3 ApplicationContext context = 4 new ClassPathXmlApplicationContext("applicationContext.xml"); 5 Animal a1 = context.getBean("cat", Animal.class); 6 a1.sayHello(); 7 Animal a2 = context.getBean("dog", Animal.class); 8 a2.sayHello(); 9 } 10}
输出结果:
1猫猫,喵~喵~ 2狗狗,旺~旺~
使用静态工厂方法创建实例时必须提供工厂类和产生实例的静态工厂方法。通过静态工厂方法创建实例时需要对Spring配置文件做如下改变;
-
class属性不在是Bean实例的实现类,而是生成Bean实例的静态工厂类
-
使用factory-method指定生产Bean实例的静态工厂方法
-
如果静态工厂方法需要参数,使用<constructor-arg />元素为其配置
当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例,在这个过程中,Spring不再负责创建Bean实例,Bean实例是由用户提供的静态工厂方法提供的。
2. 使用实例工厂方法创建Bean
实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需要使用工厂类即可,调用实例工厂方法则必须使用工厂实例。所以在Spring配置上也只有一点区别:配置静态工厂方法指定静态工厂类,配置实例工厂方法则指定工厂实例。同样是上面的例子将AnimalFactory修改为:
1public clas AnimalFactory { 2 public Animal getAnimal(String type){ //这里仅仅是去掉了static关键字 3 if ("cat".equalsIgnoreCase(type)){ 4 return new Cat(); 5 } else { 6 return new Dog(); 7 } 8 } 9}
Spring文件修改为:
1<!-- 先配置工厂类 --> 2<bean id="animalFactory" class="com.abc.AnimalFactory" /> 3<!-- 这里使用factory-bean指定实例工厂类对象 --> 4<bean id="cat" factory-bean="animalFactory" factory-method="getAnimal"> 5 <!-- 同样指定factory-method的参数 --> 6 <constructor-arg value="cat" /> 7 <property name="msg" value="猫猫" /> 8</bean> 9 10<bean id="dog" factory-bean="animalFactory" factory-method="getAnimal"> 11 <constructor-arg value="dog" /> 12 <property name="msg" value="狗狗" /> 13</bean>
测试类不用修改,输出结果和上面相同。