在这一年里一直前进,却忘记了总结,设计模式虽然在初入开发中并没有明显的体现,但是,如要在以后有更高层次的发展,设计模式是无可或缺的。这系列的文章是为了,将在学校中学习的设计模式与开发中常用的Spring结合起来,我就当大家都了解过Spring 的基本知识哈,让初学者们在摸不着的设计模式中,可以切实体会到用处。
首先,让我们从设计模式中最简单的模式也很重要的开始,也就是我们的题目《单例模式》(Singleton Pattern)。单例模式,顾名思义是一种确保某一种类只有一个,而且自行实例化并想系统提供这个实例(也就是一个全局都可以使用的对象),这种类被大家叫做单例类。单例模式是一种创建模式。一般的用途有以下几个:
1、 当我们要求一个类只有一个实例时,可使用单例模式。(如池对象例如字符串池。)
2、 当一个类需要频繁实例化,却又需要即时销毁。(资源访问对象)
像我们常用的ctrl+alt+del 调用的资源管理器,也是用了单例模式~(不信,你看看可不可以开启两个任务管理器~),哦,原来如此,总的来看,单例模式的主要是为了减少对象对系统资源的消耗。
单例模式的实现方法有两种: 懒汉式和饿汉式。
1、 懒汉式也就是在系统刚开始加载的时候,不会生成这个单例对象,在第一次使用时,才会实例化生成,之后也都是这个。
//懒汉单例模式
public class SingletonDemo {
//先定义静态变量,用以存放,生成的变量。定义为私有的是因为我们要让使用者使用我们提供的公共方法去获取这个实例而不是SingletonDemo.sld这样简单的拿到。
private static SingletonDemo sld = null;
//构造方法私有化,保证创建只能由类自己创建。。
private SingletonDemo(){}
//这个公共方法可以保证,对象的创建,只有一次,而且这有这个方法。用synchronize保证在多线程下,确保“第一次”是真的“第一次”(不要想多哈哈~)
public static synchronized SingletonDemo getInstance(){
if( sld == null){
sld = new SingletonDemo();
}
return sld;
}
}
100秒时间,仔细想想,以上的实现方法有什么不好的?
1,2,3…100
好啦,时间到啦。
真聪明,没错,这个方法存在效率问题。仔细想想,我们给方法上锁,在某一时间下,就可能只有一个线程去执行这个方法。此方法适合多线程不频繁访问,那我们换一种思路解决这个问题。
class SingletonDemo02{
//先定义静态变量,用以存放,生成的变量。定义为私有的是因为我们要让使用者使用我们提供的公共方法去获取这个实例而不是SingletonDemo.sld这样简单的拿到。
private static SingletonDemo02 sld = null;
//构造方法私有化,保证创建只能由类自己创建。
private SingletonDemo(){}
// 我们将synchronize关键字不绑定在方法上,将他绑定在类上(由于类是唯一的,所以可以这样做),
这种情况下,会比第一种效率上有所提高,因为在同一时间内,很多线程不会再方法上被阻塞了。
public static SingletonDemo02 getInstance(){
if( sld == null){
synchronized(SingletonDemo02.class){
if(sld == null){
sld = new SingletonDemo02();
}
}
}
return sld;
}
}
但是这样还是会被阻塞(因为synchronized)在频繁访问的情况下,也会有不少的线程被阻塞。
我们来看看这样。
//饿汉式单例
class SingletonDemo03{
private int[] array = new int[1024];
//类加载时创建。
private static final SingletonDemo03 sld = new SingletonDemo03();
private SingletonDemo03(){}
//这样适合频繁访问
public static SingletonDemo03 getInstance(){
return sld;
}
private static getMore(){
….
}
}
这样子创建对象。就属于饿汉式了,在类加载时,就会创建对象。此方法适合频繁访问对象。
可是,这样其实是不合理的,因为如果在SingletonDemo03类中,比如这个类很大,在我们需要调用这个类中的静态getMore方法时,这个大对象,我们会不得不创建出来。这无疑会对性能有所优化。所以此方法只适合小对象频繁调用
针对这种情况,我们借用Spring中延迟加载的策略来解决。
class SingletonDemo04{
private SingletonDemo04(){}
static class Lazy{//这个类会什么时候会加载?
public static final SingletonDemo04 slg = new SingletonDemo04();
}
public static SingletonDemo04 getInstance(){
return Lazy.slg;
}
public static void getMore(){
}
}
使用内部静态类去实现延迟加载策略。这样在访问getMore方法时并不会加载对象。在切实的调用getInstance时,才会创建这个类对象。由此,我们知道了4种不同场景下的单例模式的实现。
以上是对单例模式的一些科普,接下来我们看看在Spring中是如何使用的单例模式的?
实际上在SpringIOC中每一个注入的Bean对象默认都是单例的。我们可以通过Bean标签中的scope来实现单例模式。
具体就是这样
<bean id="gll" class="...." scope="singleton" default-lazy-init="true"/>
这样就可以得到延迟加载的单例对象,如果想要多例,可以把scope改为 prototype,这就是多例的。
在SpringBoot中可以使用@Scope("prototype")注解来实现多例。