一、单例模式概念
单例模式通俗来讲,就是要保证一个类仅有一个实例,并且提供一个访问它的全局访问点。
单例模式结构:
Singleton:负责创建Singleton的唯一实例,并提供一个getInstance()方法来访问,让外部来访问这个类的唯一实例。
单例模式应用在配置文件场景,在spring中一般采用properties和xml进行管理,这里采用properties为例进行说明如下:
@Data
public class PropertiesConfig {
/**
* 配置属性值key1
*/
private String key1;
/**
* 配置属性key2
*/
private String key2;
public PropertiesConfig() {
readProperties();
}
private void readProperties() {
Properties properties = new Properties();
InputStream
in = PropertiesConfig.class.getResourceAsStream("Properties.properties");
try {
properties.load(in);
this.key1 = properties.getProperty("key1");
this.key2 = properties.getProperty("key2");
} catch (IOException e) {
System.out.println(e.getStackTrace());
} finally {
// 关闭流,关闭流的原则是先打开后关闭
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
System.out.println(e.getStackTrace());
;
}
}
}
public static void main(String[] args) {
PropertiesConfig propertiesConfig = new PropertiesConfig();
String key1 = propertiesConfig.getKey1();
System.out.println(key1);
String key2 = propertiesConfig.getKey2();
System.out.println(key2);
}
}
上面就很简单实现获取配置文件中key对应的value值,只是通过new PerprotiesConfig()对象实例。当然问题就来了,当系统在运行期间,会存在多个PerprotiesConfig对象实例,也就是说系统中存在多份配置文件,这样一来,系统资源明显就是浪费,其实在系统获取配置文件只需要创建一个实例就可以。
二、解决方案
解决上面读取配置文件类,实力化只需实例化一次,那么单例模式出现,正好可以解决上面那个问题,代码如下:
@Data
public class PropertiesConfig {
// 初始化创建实例
private static PropertiesConfig propertiesConfig = new PropertiesConfig();
/**
* 配置属性值key1
*/
private String key1;
/**
* 配置属性key2
*/
private String key2;
/**
* 返回当前实例
*
* @return PropertiesConfig
*/
public static PropertiesConfig getInstance() {
return propertiesConfig;
}
private PropertiesConfig() {
readProperties();
}
private void readProperties() {
Properties properties = new Properties();
InputStream
in = PropertiesConfig.class.getResourceAsStream("Properties.properties");
try {
properties.load(in);
this.key1 = properties.getProperty("key1");
this.key2 = properties.getProperty("key2");
} catch (IOException e) {
System.out.println(e.getStackTrace());
} finally {
// 关闭流,关闭流的原则是先打开后关闭
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
System.out.println(e.getStackTrace());
;
}
}
}
public static void main(String[] args) {
PropertiesConfig instance = PropertiesConfig.getInstance();
String key1 = instance.getKey1();
System.out.println(key1);
String key2 = propertiesConfig.getKey2();
System.out.println(key2);
}
}
从上面代码可以看出,在类直接初始化实例类,这样全局就是只初始化一次数据,在需要获取配置文件中key时,只需要获取getInsance().get属性值。这样就解决上面多次实例化问题。
单例模式包含饿汉式和懒汉式
所谓饿汉式就是空间换时间,当类加载时候就去创建实例,不管能不能用上,先创建,每次调用时候就不需要再做判断,这样可以节约时间,且饿汉式式线程安全的。饿汉式代码如下:
@Data
public class Singleton {
private String pram; // 类属性
private static Singleton singleton = new Singleton(); // 初始化实例
/**
* 获取对象实例
*
* @return Singleton
*/
public static Singleton getInstance() {
return singleton;
}
/**
* 私有方法构造,可以在内部控制创建实例的数目
*/
private Singleton() {
}
/**
* 示意方法,单独可以有自己操作
*/
private void singletonOperation() {
// 功能实现
}
}
所谓懒汉式就是时间换空间,当类加载时候,首先要去判断是否已创建实例,如果没有就直接创建,这样一来就浪费时间,可以节约空间,且线程是不安全的(解决线程不安全可以加锁)。懒汉式代码 如下:
@Data
public class Singleton {
private String pram; // 类属性
private static Singleton singleton = null; // 初始化实例
/**
* 获取对象实例
*
* @return Singleton
*/
public static synchronized Singleton getInstance() {
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
/**
* 私有方法构造,可以在内部控制创建实例的数目
*/
private Singleton() {
}
/**
* 示意方法,单独可以有自己操作
*/
private void singletonOperation() {
// 功能实现
}
}
懒汉式加锁实现方式有几种,待下次更新单例模式模型讲解