Spring工厂方法创建(实例化)bean实例代码

 更新时间:2018年01月10日 10:05:06   作者:duanxz  
这篇文章主要介绍了Spring工厂方法创建bean实例代码,具有一定借鉴价值,需要的朋友可以参考下

目标明确

简单叙述一下本文想要解决的问题:如何在Spring中不再使用Spring创建Bean实例,而是把Bean创建过程转移到开发者手中。

思路清晰

创建Bean实例的方式:

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

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

2) 通过静态工厂方法

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

注: 工厂类实例没有创建

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

方式:

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

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

注: 工厂类实例被创建

方法实用

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

输出结果:

<code class="hljs">猫猫,喵~喵~
狗狗,旺~旺~</code>

使用静态工厂方法创建实例时必须提供工厂类和产生实例的静态工厂方法。通过静态工厂方法创建实例时需要对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的三种方式。

抽象接口:

public interface IMusicBox { 
   public void play(); 
} 

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

工厂类:

public class MusicBoxFactory { 
  public static IMusicBox createMusicBox(){ 
  return new IMusicBox(){ 
       public void play(){ 
    System.out.println("Play piano..."); 
     } 
  }; 
  } 
} 

配置文件:

<bean id="musicBox" class="test.spring.MusicBoxFactory" factory-method="createMusicBox" /> 

测试类:

public static void main(String[] args) { 
  ApplicationContext ctx =  
  new ClassPathXmlApplicationContext("bean-config.xml"); 
  IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox"); 
  musicbox.play(); 
} 

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

工厂类:

public class MusicBoxFactory { 
  public IMusicBox createMusicBox(){//没有static修饰 
  return new IMusicBox(){ 
       public void play(){ 
    System.out.println("Play piano..."); 
     } 
  }; 
  } 
} 

配置文件:

<bean id="factoryBean" class="test.spring.MusicBoxFactory" /> 
<bean id="musicBox" factory-bean="factoryBean" factory-method="createMusicBox" /> 

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

测试类:

public static void main(String[] args) { 
  ApplicationContext ctx =  
  new ClassPathXmlApplicationContext("bean-config.xml"); 
  IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox"); 
  musicbox.play(); 
} 

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

工厂类:

import org.springframework.beans.factory.FactoryBean; 
 
public class MusicBoxFactory2 implements FactoryBean { 
  public Object getObject() throws Exception { 
  return new IMusicBox(){ 
    public void play(){ 
       System.out.println("Play piano..."); 
       } 
  }; 
  } 
 
  public Class getObjectType() { 
  return IMusicBox.class; 
  } 
 
  public boolean isSingleton() { 
  return false; 
  } 
} 

配置文件:

<bean id="musicBox" class="test.spring.MusicBoxFactory2"/> 

测试类:

public static void main(String[] args) { 
  ApplicationContext ctx =  
  new ClassPathXmlApplicationContext("bean-config.xml"); 
  //不加 & 返回工厂的“产品” 
  IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox"); 
  musicbox.play(); 
  //加 & 返回工厂类实例 
  Object obj = ctx.getBean("&musicBox");  
  System.out.println(obj.getClass().getName());  
 
} 

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

总结

Spring工厂方法实例化bean实例的介绍就到这里,有什么不足之处,大家可以留言指出。感谢朋友们对本站的支持!

相关文章

  • spring 参数校验Validation示例详解

    spring 参数校验Validation示例详解

    Spring提供了Validation工具类来实现对客户端传来的请求参数的有效校验,本文给大家介绍spring 参数校验Validation示例详解,感兴趣的朋友一起看看吧
    2024-12-12
  • Java实现简易提款机

    Java实现简易提款机

    这篇文章主要为大家详细介绍了Java实现简易提款机,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Spring AI借助全局参数实现智能数据库操作与个性化待办管理

    Spring AI借助全局参数实现智能数据库操作与个性化待办管理

    这篇文章主要介绍了Spring AI借助全局参数实现智能数据库操作与个性化待办管理,本文给大家介绍的非常详细,需要的朋友可以参考下
    2024-11-11
  • Java Map 按照Value排序的实现方法

    Java Map 按照Value排序的实现方法

    Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。这篇文章主要介绍了Java Map 按照Value排序的实现方法,需要的朋友可以参考下
    2016-08-08
  • IntelliJ IDEA 安装教程2019.09.23(最新版)

    IntelliJ IDEA 安装教程2019.09.23(最新版)

    本文通过图文并茂的形式给大家介绍了IntelliJ IDEA 安装教程2019.09.23最新版,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • 深入了解Spring Boot2.3.0及以上版本的Liveness和Readiness功能

    深入了解Spring Boot2.3.0及以上版本的Liveness和Readiness功能

    这篇文章主要介绍了Spring Boot2.3.0及以上版本的Liveness和Readiness功能示例深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 简单了解SpringCloud运行原理

    简单了解SpringCloud运行原理

    这篇文章主要介绍了简单了解SpringCloud运行原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • java poi实现Excel多级表头导出方式(多级表头,复杂表头)

    java poi实现Excel多级表头导出方式(多级表头,复杂表头)

    文章介绍了使用javapoi库实现Excel多级表头导出的方法,通过主代码、合并单元格、设置表头单元格宽度、填充数据、web下载和提供表头样式、内容样式以及标题样式等步骤,作者实现了最终的效果
    2025-01-01
  • Java中字节流和字符流的区别与联系

    Java中字节流和字符流的区别与联系

    Java中的字节流和字符流是用于处理输入和输出的两种不同的流,本文主要介绍了Java中字节流和字符流的区别与联系,字节流以字节为单位进行读写,适用于处理二进制数据,本文结合实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2024-12-12
  • mybatis整合spring实现开启mapper.xml映射文件扫描

    mybatis整合spring实现开启mapper.xml映射文件扫描

    这篇文章主要介绍了mybatis整合spring实现开启mapper.xml映射文件扫描,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10

最新评论