转:Spring使用静态工厂方法创建Bean

如何在Spring中不再使用Spring创建Bean实例,而是把Bean创建过程转移到开发者手中。

1. 使用静态工厂方法创建Bean

    使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类。因为Spring需要知道是用哪个工厂来创建Bean实例。另外,还需要使用factory-method来指定静态工厂方法名,Spring将调用静态工厂方法(可能包含一组参数),来返回一个Bean实例,一旦获得了指定Bean实例,Spring后面的处理步骤与采用普通方法创建Bean实例则完全一样。需要注意的是,当使用静态工厂方法来创建Bean时,这个factory-method必须要是静态的。这段阐述听上去有点晕,话不多说,上代码:

    先定义一个接口,静态方法产生的将是该接口的实例:

?
1
2
3
public  interface  Animal {
     public  void  sayHello();
}

    下面是接口的两个实现类:

?
1
2
3
4
5
6
7
8
9
10
11
public  class  Cat  implements  Animal {
     private  String msg;
     //依赖注入时必须的setter方法
     public  void  setMsg(String msg){
         this .msg = msg;
     }
     @Override
     public  void  sayHello(){
         System.out.println(msg +  ",喵~喵~" );
     }
}
?
1
2
3
4
5
6
7
8
9
10
11
public  class  Dog  implements  Animal {
     private  String msg;
     //依赖注入时必须的setter方法
     public  void  setMsg(String msg){
         this .msg = msg;
     }
     @Override
     public  void  sayHello(){
         System.out.println(msg +  ",旺~旺~" );
     }
}

    下面的AnimalFactory工厂中包含了一个getAnimal的静态方法,该方法将根据传入的参数决定创建哪个对象。这是典型的静态工厂设计模式。

?
1
2
3
4
5
6
7
8
9
public  clas AnimalFactory {
     public  static  Animal getAnimal(String type){
         if  ( "cat" .equalsIgnoreCase(type)){
             return  new  Cat();
         else  {
             return  new  Dog();
         }
     }
}

    如果需要指定Spring使用AnimalFactory来产生Animal对象,则可在Spring配置文件中作如下配置:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 配置AnimalFactory的getAnimal方法,使之产生Cat -->
< bean  id = "cat"  class = "com.abc.AnimalFactory"  factory-method = "getAnimal" >
     <!-- 配置静态工厂方法的参数,getAnimal方法将产生Cat类型的对象 -->
     < constructor-arg  value = "cat"  />
     <!-- 通过setter注入的普通属性 -->
     < property  name = "msg"  value = "猫猫"  />
</ bean >
<!-- 配置AnimalFactory的getAnimal方法,使之产生Dog -->
< bean  id = "dog"  class = "com.abc.AnimalFactory"  factory-method = "getAnimal" >
     <!-- 配置静态工厂方法的参数,getAnimal方法将产生Dog类型的对象 -->
     < constructor-arg  value = "dog"  />
     <!-- 通过setter注入的普通属性 -->
     < property  name = "msg"  value = "狗狗"  />
</ bean >

    从上面的配置可以看出:cat和dog两个Bean配置的class和factory-method完全相同,这是因为两个实例都使用同一个静态工厂类、同一个静态工厂方法产生得到的。只是为这个静态工厂方法指定的参数不同,使用<constructor-arg />元素来为静态工厂方法指定参数。

    主程序获取cat和dog两个Bean实例的方法不变,同样只需要调用Spring容器的getBean()即可:

?
1
2
3
4
5
6
7
8
9
10
public  class  Test {
     public  static  void  main(String args[]){
         ApplicationContext context = 
                 new  ClassPathXmlApplicationContext( "applicationContext.xml" );
         Animal a1 = context.getBean( "cat" , Animal. class );
         a1.sayHello();
         Animal a2 = context.getBean( "dog" , Animal. class );
         a2.sayHello();
     }
}

    输出结果:

?
1
2
猫猫,喵~喵~
狗狗,旺~旺~

    使用静态工厂方法创建实例时必须提供工厂类和产生实例的静态工厂方法。通过静态工厂方法创建实例时需要对Spring配置文件做如下改变;

  • class属性不在是Bean实例的实现类,而是生成Bean实例的静态工厂类

  • 使用factory-method指定生产Bean实例的静态工厂方法

  • 如果静态工厂方法需要参数,使用<constructor-arg />元素为其配置

    当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例,在这个过程中,Spring不再负责创建Bean实例,Bean实例是由用户提供的静态工厂方法提供的。


2. 使用实例工厂方法创建Bean

    实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需要使用工厂类即可,调用实例工厂方法则必须使用工厂实例。所以在Spring配置上也只有一点区别:配置静态工厂方法指定静态工厂类,配置实例工厂方法则指定工厂实例。同样是上面的例子将AnimalFactory修改为:

?
1
2
3
4
5
6
7
8
9
public  clas AnimalFactory {
     public  Animal getAnimal(String type){   //这里仅仅是去掉了static关键字
         if  ( "cat" .equalsIgnoreCase(type)){
             return  new  Cat();
         else  {
             return  new  Dog();
         }
     }
}

    Spring文件修改为:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 先配置工厂类 -->
< bean  id = "animalFactory"  class = "com.abc.AnimalFactory"  />
<!-- 这里使用factory-bean指定实例工厂类对象 -->
< bean  id = "cat"  factory-bean = "animalFactory"  factory-method = "getAnimal" >
     <!-- 同样指定factory-method的参数 -->
     < constructor-arg  value = "cat"  />
     < property  name = "msg"  value = "猫猫"  />
</ bean >
 
< bean  id = "dog"  factory-bean = "animalFactory"  factory-method = "getAnimal" >
     < constructor-arg  value = "dog"  />
     < property  name = "msg"  value = "狗狗"  />
</ bean >

    测试类不用修改,输出结果和上面相同。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值