spring中的单例与java中的单例

来源:互联网 发布:淘宝全网举报假货最快 编辑:程序博客网 时间:2024/06/05 22:50

一、概述:

 1、spring单例通过设置属性scope="Singleton"完成(默认),其概念和java中的单例概念一致,如在web应用中,每次请求使用的是同一个实例对象。但spring的单例仅限制在其上下文环境中,并没有限制你通过其他方式去创建此对象的其他实例。说白了是spring帮你完成模拟的单例创建,使用。

2、Spring中的单例和设计模式中的单例思想是一样的,不过它不需要编程来实现单例,而是由容器来配置是否单例。即消除了程序性单例

 

二、传统的单例模式的实现方式

1. 最原始的实现单例模式的方法(存在线程不安全):

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)时,一个线程判断了当前为空,然后切换到另一个线程,这个线程也判断为空。然后切换回第一个线程,进行实例化,再切换到第二个线程,进行实例化。这样就存在了两个实例。

 

2. 通过关键字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会同步的进行,不会有线程安全问题,但是不仅仅是实例化,每次调用也需要同步,这样就会造成很多资源的浪费。

 

3. 通过静态内部类进行单例

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

1.applicationContext.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-lazy-init="false">

 <bean id="Test_pojo" class="cn.wy.test_singleton.Test_pojo">
  <property name="age" value="10" />
  <property name="name" value="xiaoming" />
  <property name="height" value="30" />
 </bean>

 <bean id="SingletonThree" class="cn.wy.test_singleton.SingletonThree" factory-method="getInstance">
  <property name="name" value="wy_test" />
  <property name="pojo" ref="Test_pojo" />
 </bean>
</beans>

 

2.Test_pojo类如下:

package cn.wy.test_singleton;

/**  
 * @Description: TODO
 * @author wangy  
 * @date 2015年12月31日 下午3:52:50
 */
public class Test_pojo {
 private int age = 0;
 private String name = "unkown";
 private int height = 0;
 public int getAge() {
  return age;
 }
 public String getName() {
  return name;
 }
 public int getHeight() {
  return height;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public void setName(String name) {
  this.name = name;
 }
 public void setHeight(int height) {
  this.height = height;
 }
}

 

3.Singleton类如下:

package cn.wy.test_singleton;

/**  
 * @Description: 单例模式3
 * @author wangy  
 * @date 2015年12月31日 下午3:39:45
 */
public class SingletonThree {
 private Test_pojo pojo = new Test_pojo();
 private String name = "unkown";
 
 private SingletonThree() {}
 private static class SingletonHolder{
  static SingletonThree instance = new SingletonThree();
 }
 public static SingletonThree getInstance() {
  return SingletonHolder.instance;
 }
 public Test_pojo getPojo() {
  return pojo;
 }
 public void setPojo(Test_pojo pojo) {
  this.pojo = pojo;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 
}

 

4.测试类:

package cn.wy.task_schedule;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.wy.test_singleton.SingletonThree;

public class Application {
 
 public static void main(String[] args) {
  String[] path= new String[] { 
    "classpath*:applicationContext-testSingleton.xml"
    };
  try {
   ApplicationContext context = new ClassPathXmlApplicationContext(path);
   SingletonThree singleton1 = SingletonThree.getInstance();
   SingletonThree singleton2 = (SingletonThree) context.getBean("SingletonThree");
   System.out.println("o1'code: " + singleton1.hashCode() + ", o2's code:" + singleton2.hashCode());
   System.out.println("starting");
     } catch (Exception e) {
   // TODO: handle exception
  }
 }

}

     解释:在配置文件中定义"SingletonThree"的bean时候,如果有factory-method="getInstance",则上面示例中的singleton1、singleton2是同一个对象,里面的属性均一致;如果没有factory-method="getInstance",则上面示例中的singleton1、singleton2是两个不同的对象,singleton2中的Test_pojo对象是被赋过值之后的对象,而singleton1中的Test_pojo对象是仅有初始值的对象。

0 0
原创粉丝点击