首先要明确一个概念,Singleton 模式是什么?
这里的Singleton 模式是指只被实例化一次的类,比如一个线程安全的单例模式,一个线程安全的静态内部类模式,一个线程安全的静态工厂模式,而非设计模式中的单例模式。
参考《Effective Java》,开篇就介绍了 考虑使用静态工厂方法代替构造器,至于原因,这里不再赘述,仅简单的介绍如何实现这种方式的。想要了解的小伙伴可以去看下书中的内容,作者讲的很详细。
这种方式创建的实例是线程安全的,因为他创建的实例时唯一的,在多线程环境下,每个线程都要进行同步,这样会浪费大量的时间。
通常这种模式的使用情况为,系统需要一个全局的、不需要通过子类来做额外拓展的、仅需要创建一次实例会话的(这种模式无法通过子类来做额外的拓展,因为构造函数是私有的),最常见的两种创建方式,是将构造函数设置为private。
这种模式的好处在于,我们可以在系统任意一处随时调用,而不用担心他会创建多个实例。
1. 通过创建私有的构造函数防止外部调用,这样就可以保证实例只被创建一次,保证了全局的唯一性。
2. 实例一旦创建,则不能再次被创建,保证了全局的唯一性。
本文章使用http调用第三方接口的例子来描述,通过使用Singleton模式,对第三方接口做统一管理。
第一种方法,构造函数私有方式 。
私有构造函数,公共静态成员
使用private修饰构造函数,使用final修饰公有的静态成员。
在Effective Java中,称之为公有域方法。也是这本书作者第一推荐的方法。
public class GlobalApi{
@Autowired
private CloudApiService cloudApiService;
private String host;
// 公有的静态成员
public static final GlobalApi INSTANCE=new GlobalApi();
// 1. 需要注意的是,我们可以通过AccessibleObject.setAccessible方法,通过反射来调用私有的构造函数。
// 2. 如果需要规避这种方式,可以在被创建第二个实例的时候,通过手动抛出异常来实现,避免出现多个实例的情况。
private GlobalApi(){
// 2-1. 判断是否已经创建过实例,如果已经创建过,手动抛出异常。
if(Objects.nonNull(GlobalApi.instance)){
throw new RuntimeException("Singleton已经被创建");
}
String baseHost=cloudApiService.getBaseHost();
if(