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实例的介绍就到这里,有什么不足之处,大家可以留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • Spring循环依赖正确性及Bean注入的顺序关系详解

    一.前言 我们知道 Spring 可以是懒加载的,就是当真正使用到 Bean 的时候才实例化 Bean.当然也不全是这样,例如配置 Bean 的 lazy-init 属性,可以控制 Spring 的加载时机.现在机器的性能.内存等都比较高,基本上也不使用懒加载,在容器启动时候来加载bean,启动时间稍微长一点儿,这样在实际获取 bean 供业务使用时,就可以减轻不少负担,这个后面再做分析. 我们使用到 Bean 的时候,最直接的方式就是从 Factroy 中获取,这个就是加载 Bean 实例的源

  • Spring的实例工厂方法和静态工厂方法实例代码

    Spring的实例工厂方法和静态工厂方法都可以用来实例化bean,本文我们就来看看相关实例. 静态工厂方法:直接调用静态方法可以返回Bean的实例 package com.zhu.string.factory; import java.util.HashMap; import java.util.Map; public class StaticCarFactory { /** * 静态工厂方法:直接调用静态方法可以返回Bean的实例 * */ private static Map<String

  • 浅谈Spring5 响应式编程

    近年来,响应式编程在开发者社区和客户中很受欢迎,由于其以声明的方式构建应用程序的能力,而不是强制,形成更加敏感和有弹性的应用.Spring 5 将反应系统纳入其核心框架的事实已经显示出向声明式编程的范式转变. 响应式编程管理数据生产者和消费者之间的异步数据流,它们需要以流畅的方式对数据进行响应.所以,响应式编程都是异步和事件驱动的流畅应用程序,需要少量的线程进行缩放. 响应式编程很难构建基于线程的架构,由于在基于共享可变状态.线程和锁的应用程序扩展过程中涉及到高度复杂性. 在响应式编程的上下文中

  • 浅谈SpringBoot之开启数据库迁移的FlyWay使用

    本文介绍了SpringBoot开启数据库迁移的FlyWay使用,分享给大家,具体如下: 一,首先我先了解下FlyWay是如何运转的. 最简单的方案是将Flyway指向一个空数据库. 它将尝试找到其元数据表.当数据库为空时,Flyway将不会找到它, 而是创建它.您现在拥有一个名为SCHEMA_VERSION的单个空表的数据库 : 该表将用于跟踪数据库的状态.之后,Flyway将开始扫描应用程序的文件系统或类路径进行迁移.它们可以用Sql或Java编写. 然后根据其版本号对迁移进行排序,并按顺序应

  • 浅谈SpringMVC中post checkbox 多选框value的值(隐藏域方式)

    我这里往后端传递checkbox 多选框value的值是通过字符串方式传递,先调用js对选定checkbox遍历获取选的的boxvalue,然后写进隐藏域,最后作文对象的属性提交.见代码:` 前端: <form:form commandName="user" method="post"> <c:forEach items="${deploys}" var="deploy" varStatus="de

  • 从SpringMVC迁移到Springboot的方法步骤

    在将SpringMVC项目转移到Springboot上的过程中,主要做了以下的事情 Profile配置 全局变量从properties文件读入 数据源与Mybatis配置 日志文件配置 WebConfig配置(包括原有的web.xml和spring-mvc.xml) 去掉多余的bean注入 本篇文章除了介绍做了些什么和怎么做之外,会多很多多余的废话,关于对原理的一些探讨,知其然也要知其所以然. Profile配置 在传统的Spring项目中,多个profile的配置方式首先是在pom.xml文件

  • Intellij IDEA 2017新特性之Spring Boot相关特征介绍

    前言 Intellij IDEA 2017.2.2版本针对Springboot设置了一些特性,本篇文章给大家简单介绍一下如何使用这些特性. Run Dashboard 针对Spring boot提供了Run Dashboard方式的来代替传统的run方法.下面看一下官网提供的面板结构图: 是不是很炫,直接可以通过Dashboard看到Springboot的启动项目,并显示相应的端口等信息,同时还能在这里进行相应的操作.下面我们来看看如何调用出Dashboard. 首先,你的项目应该是一个spri

  • jQuery+SpringMVC中的复选框选择与传值实例

    一.checkbox选择 在jQuery中,选中checkbox通用的两种方式: $("#cb1").attr("checked","checked"); $("#cb1").attr("checked",true); 对应的jQuery函数,主要完成三个功能: 1.第一个复选框选中或取消选中,则下面的复选框为全选或取消全选: 2.当下面的复选框全部选中时,则将第一个复选框设置为选中,当下面的复选框中有一个

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

    目标明确 简单叙述一下本文想要解决的问题:如何在Spring中不再使用Spring创建Bean实例,而是把Bean创建过程转移到开发者手中. 思路清晰 创建Bean实例的方式: 1) 通过构造器(有参或无参) 方式: <bean id="" class=""/> 2) 通过静态工厂方法 方式: <bean id="" class="工厂类" factory-method="静态工厂方法"/

  • java 工厂方法详解及实例代码

    工厂方法概述 工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现. 优点 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性 缺点 需要额外的编写代码,增加子工作量 public class IntegerDemo { public static void main(String[] args) { Factory factory = ne

  • java  工厂方法详解及实例代码

    工厂方法概述 工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现. 优点 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性 缺点 需要额外的编写代码,增加子工作量 public class IntegerDemo { public static void main(String[] args) { Factory factory = ne

  • Spring启动后获取所有拥有特定注解的Bean实例代码

    本文研究的主要是Spring启动后获取所有拥有特定注解的Bean,具体如下. 最近项目中遇到一个业务场景,就是在Spring容器启动后获取所有的Bean中实现了一个特定接口的对象,第一个想到的是ApplicationContextAware,在setApplicationContext中去通过ctx获取所有的bean,后来发现好像逻辑不对,这个方法不是在所有bean初始化完成后实现的,后来试了一下看看有没有什么Listener之类的,发现了好东西ApplicationListener,然后百度一

  • Spring实战之调用实例工厂方法创建Bean操作示例

    本文实例讲述了Spring实战之调用实例工厂方法创建Bean操作.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" x

  • Spring实战之使用静态工厂方法创建Bean操作示例

    本文实例讲述了Spring实战之使用静态工厂方法创建Bean操作.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" x

  • Java之Spring注解配置bean实例代码解析

    前面几篇均是使用xml配置bean,如果有上百个bean,这是不可想象的.故而,请使用注解配置bean !!! [1]注解类别 @Component : 基本注解, 标识了一个受 Spring(点击这里可以下载<Spring应用开发完全手册>) 管理的组件 @Repository : 标识持久层组件 @Service : 标识服务层(业务层)组件 @Controller : 标识表现层组件 Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件. 对于扫描到的组

  • Spring组件自动扫描详解及实例代码

    Spring组件自动扫描详解及实例代码 问题描述 一个系统往往有成千上万的组件,如果需要手动将所有组件都纳入spring容器中管理,是一个浩大的工程. 解决方案 Spring 提供组件扫描(component scanning)功能.它能从classpath里自动扫描.侦测和实例化具有特定注解的组件.基本的注解是@Component,它标识一个受Spring管理的组件.其他特定的注解有@Repository.@Service和@Controller,它们分别标识了持久层.服务处和表现层的组件.

  • Spring Security 图片验证码功能的实例代码

    验证码逻辑 以前在项目中也做过验证码,生成验证码的代码网上有很多,也有一些第三方的jar包也可以生成漂亮的验证码.验证码逻辑很简单,就是在登录页放一个image标签,src指向一个controller,这个Controller返回把生成的图片以输出流返回给页面,生成图片的同时把图片上的文本放在session,登录的时候带过来输入的验证码,从session中取出,两者对比.这位老师讲的用Spring Security集成验证码,大体思路和我说的一样,但更加规范和通用些. spring securi

  • Python线程池thread pool创建使用及实例代码分享

    目录 前言 一.线程 1.线程介绍 2.线程特性 轻型实体 独立调度和分派的基本单位 可并发执行 4)共享进程资源 二.线程池 三.线程池的设计思路 四.Python线程池构建 1.构建思路 2.实现库功能函数 ThreadPoolExecutor() submit() result() cancel() cancelled() running() as_completed() map() 前言 首先线程和线程池不管在哪个语言里面,理论都是通用的.对于开发来说,解决高并发问题离不开对多个线程处理

随机推荐