Spring工厂方式创建Bean实例

创建Bean实例的方式:

   1) 通过构造器(有参或无参) 

      方式: <bean id="" class=""/>

   2) 通过静态工厂方法

      方式: <bean id="" class="工厂类" factory-method="静态工厂方法"/>

      注: 工厂类实例没有创建

   3) 通过实例工厂方法(非静态方法)

      方式:

        <bean id="factory" class="工厂类"/>

        <bean id="" factory-bean="factory" factory-method="实例工厂方法"/>

      注: 工厂类实例被创建

==========================================

摘要

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

示例1:

需求:

1 不想再bean.xml加载的时候实例化bean,而是想把加载bean.xml与实例化对象分离。

  2 实现单例的bean

以上的情况,都可以通过工厂方法factory-method来创建bean

这样再加载bean.xml时,不会直接实例化bean,而是当调用factory-method所指的方法时,才开始真正的实例化。

实现:通过spring的factory-method来创建单例的bean

  首先通过静态内部类创建一个单例对象

复制代码
package com.spring.test.factorymethod;

public class Stage {
    public void perform(){
        System.out.println("演出开始...");
    }
    private Stage(){
        
    }
    private static class StageSingletonHolder{
        static Stage instance = new Stage();
    }
    public static Stage getInstance(){
        return StageSingletonHolder.instance;
    }
}
复制代码

  在spring配置文件中指定加载的方法getInstance

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd">
     <bean id="theStage" class="com.spring.test.factorymethod.Stage"
         factory-method="getInstance"></bean>
</beans>
复制代码

  通过应用上下文调用bean获取实例

复制代码
package com.spring.test.factorymethod;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
        Stage stage = ((Stage)ctx.getBean("theStage"));//.getInstance();
        stage.perform();
    }
}
复制代码

  执行结果

复制代码
一月 24, 2015 6:38:18 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@512dbd1a: startup date [Sat Jan 24 18:38:18 CST 2015]; root of context hierarchy
一月 24, 2015 6:38:19 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [bean.xml]
一月 24, 2015 6:38:19 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2d1879ea: defining beans [duke,sonnet29,poeticDuke,theStage]; root of factory hierarchy
演出开始...

 

 二、工厂方法创建bean介绍

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

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

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

public interface Animal {
    public void sayHello();
}

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

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 + ",喵~喵~");
    }
}
 

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的静态方法,该方法将根据传入的参数决定创建哪个对象。这是典型的静态工厂设计模式。

public clas AnimalFactory {
    public static Animal getAnimal(String type){
        if ("cat".equalsIgnoreCase(type)){
            return new Cat();
        } else {
            return new Dog();
        }
    }
}

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

<!-- 配置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()即可:

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();
    }
}

    输出结果:

猫猫,喵~喵~
狗狗,旺~旺~

 

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

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

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

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

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

 

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

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

public clas AnimalFactory {
    public Animal getAnimal(String type){  //这里仅仅是去掉了static关键字
        if ("cat".equalsIgnoreCase(type)){
            return new Cat();
        } else {
            return new Dog();
        }
    }
}

    Spring文件修改为:

<!-- 先配置工厂类 -->
<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>

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

 

=============================================================

很多情况下使用<bean id=”bean1” class=”…” />定义一个bean,这种定义方式Spring将会调用默认的无参数构造方法创建Bean实例。除此之外还可以使用工厂方式创建Bean实例,实现Bean创建与使用的分离,将Bean创建工作交由工厂来完成。 
配置工厂Bean的三种方式。 
抽象接口: 

Java代码   收藏代码
  1. public interface IMusicBox {  
  2.      public void play();  
  3. }  


1、静态工厂方法取得Bean实例 
工厂类: 

Java代码   收藏代码
  1. public class MusicBoxFactory {  
  2.     public static IMusicBox createMusicBox(){  
  3.     return new IMusicBox(){  
  4.               public void play(){  
  5.         System.out.println("Play piano...");  
  6.          }  
  7.     };  
  8.     }  
  9. }  


配置文件: 

Xml代码   收藏代码
  1. <bean id="musicBox" class="test.spring.MusicBoxFactory" factory-method="createMusicBox" />  


测试类: 

Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.     ApplicationContext  ctx =   
  3.     new ClassPathXmlApplicationContext("bean-config.xml");  
  4.     IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox");  
  5.     musicbox.play();  
  6. }  



2、工厂实例的方法取得Bean实例 
工厂类: 

Java代码   收藏代码
  1. public class MusicBoxFactory {  
  2.     public IMusicBox createMusicBox(){//没有static修饰  
  3.     return new IMusicBox(){  
  4.               public void play(){  
  5.         System.out.println("Play piano...");  
  6.          }  
  7.     };  
  8.     }  
  9. }  



配置文件: 

Xml代码   收藏代码
  1. <bean id="factoryBean"  class="test.spring.MusicBoxFactory" />  
  2. <bean id="musicBox" factory-bean="factoryBean" factory-method="createMusicBox" />  


“factory-bean”属性指定工厂Bean,”factory-method”属性指定工厂方法来取得Bean实例。 

测试类: 

Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.     ApplicationContext  ctx =   
  3.     new ClassPathXmlApplicationContext("bean-config.xml");  
  4.     IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox");  
  5.     musicbox.play();  
  6. }  



3、工厂类实现org.springframework.beans.factory.FacotryBean接口 
工厂类: 

Java代码   收藏代码
  1. import org.springframework.beans.factory.FactoryBean;  
  2.   
  3. public class MusicBoxFactory2 implements FactoryBean {  
  4.     public Object getObject() throws Exception {  
  5.     return new IMusicBox(){  
  6.         public void play(){  
  7.              System.out.println("Play piano...");  
  8.               }  
  9.     };  
  10.     }  
  11.   
  12.     public Class getObjectType() {  
  13.     return IMusicBox.class;  
  14.     }  
  15.   
  16.     public boolean isSingleton() {  
  17.     return false;  
  18.     }  
  19. }  



配置文件: 

Xml代码   收藏代码
  1. <bean id="musicBox" class="test.spring.MusicBoxFactory2"/>  



测试类: 

Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.     ApplicationContext  ctx =   
  3.     new ClassPathXmlApplicationContext("bean-config.xml");  
  4.     //不加 & 返回工厂的“产品”  
  5.     IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox");  
  6.     musicbox.play();  
  7.     //加 & 返回工厂类实例  
  8.     Object obj = ctx.getBean("&musicBox");    
  9.     System.out.println(obj.getClass().getName());   
  10.   
  11. }  


实现FactoryBean接口的类不会被视为普通的Bean,Spring会自动检测,调用getObject方法获取Bean实例

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值