博客主页: 南来_北往
系列专栏:Spring Boot实战
工厂方法模式
在Spring中,可以使用工厂方法模式来创建单例Bean。工厂方法模式是一种创建对象的方式,它允许我们在运行时动态地决定要实例化哪个类的对象。
以下是使用工厂方法创建单例Bean的步骤:
1、建一个接口或抽象类,定义一个工厂方法,该方法返回所需的Bean类型。例如,我们可以创建一个名为MyBeanFactory
的接口,其中包含一个名为createMyBean
的方法:
public interface MyBeanFactory {
MyBean createMyBean();
}
2、实现该接口或抽象类的工厂类。在这个例子中,我们将创建一个名为MyBeanFactoryImpl
的类来实现MyBeanFactory
接口:
public class MyBeanFactoryImpl implements MyBeanFactory {
@Override
public MyBean createMyBean() {
return new MyBean();
}
}
3、在Spring配置文件中配置工厂bean。我们需要将工厂bean定义为单例(singleton),以确保在整个应用程序中只有一个实例被创建。这可以通过在bean的定义中使用scope="singleton"
属性来完成:
<bean id="myBeanFactory" class="com.example.MyBeanFactoryImpl" scope="singleton"/>
4、在需要使用Bean的地方注入工厂bean并调用工厂方法。例如,在一个名为MyService
的服务类中,我们可以注入MyBeanFactory
并使用它来创建MyBean
实例:
@Service
public class MyService {
private final MyBeanFactory myBeanFactory;
@Autowired
public MyService(MyBeanFactory myBeanFactory) {
this.myBeanFactory = myBeanFactory;
}
public void doSomething() {
MyBean myBean = myBeanFactory.createMyBean();
// 使用myBean执行操作...
}
}
通过这种方式,我们可以根据需要在运行时动态地创建和管理单例Bean。
但是如果有这样的需求:>
1、不想再bean.xml加载的时候实例化bean,而是想把加载bean.xml与实例化对象分离。
2、实现单例的bean
以上的情况,都可以通过工厂方法factory-method来创建bean。
这样再加载bean.xml时,不会直接实例化bean,而是当调用factory-method所指的方法时,才开始真正的实例化。
首先看一下传统的单例模式的实现方式:
实现单例模式的方法(存在线程不安全)
public class SingletonOne {
private static SingletonOne instance = null;
private SingletonOne() {}
public static SingletonOne getInstance() {
if (instance == null) {
instance = new SingletonOne();
}
return instance;
}
}
但是这种方法有一个弊端,就是存在线程的不安全!
比如当两个线程同时进入if(instance == null)时,一个线程判断了当前为空,然后切换到另一个线程,这个线程也判断为空。然后切换回第一个线程,进行实例化,再切换到第二个线程,进行实例化。这样就存在了两个实例。
通过关键字Synchronized强制线程同步
package com.something.singleton;
public class SingletonTwo {
private static SingletonTwo instance = null;
private SingletonTwo() {}
public static synchronized SingletonTwo getInstance() {
if (instance == null) {
instance = new SingletonTwo();
}
return instance;
}
}
这样当线程进行到getInstance会同步的进行,不会有线程安全问题,但是不仅仅是实例化,每次调用也需要同步,这样就会造成很多资源的浪费。
通过静态内部类进行单例
public class SingletonThree {
private static class SingletonHolder{
static SingletonThree instance = new SingletonThree();
}
private SingletonThree() {}
public static SingletonThree getInstance() {
return SingletonHolder.instance;
}
}
这种方法时最推荐的一种方法,由于Java的调用机制,SingletonHolder只有在调用getInstance的时候才会加载,而内部的静态类只会被加载一次,因此又是线程安全的。
总结起来:
第一种方法,是存在线程安全问题的。
第二种方法,则消耗了一定的资源。
第三种方法,比较推荐。
通过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
演出开始...