Spring的单例模式底层实现学习笔记
单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例。
单例模式有以下的特点:
①
单例类只能有一个实例
②
单例类必须自己创建自己的唯一实例
③
单例类必须给所有其他对象提供这一实例
下面我们就来写一个简单的单例模式的例子
package spring;
public class SingletonWW {
private static final SingletonWW instance=new SingletonWW();
//私有的默认构造函数
private SingletonWW(){}
//静态工厂方法
public static SingletonWW getInstance(){
return instance;
}
}
大家可以看出来,在这个类被加载时,静态变量instance会被初始化,此时该类的私有构造函数被调用,这时候,单例类的唯一实例就被创建出来了
值得注意的是:由于构造函数是私有的,因此该类不能被继承
还有一种写法也可以实现单例模式:
package spring;
public class SingletonWW {
private static SingletonWW instance = null;
//私有的默认构造函数
private SingletonWW(){}
//静态工厂方法
public synchronized static SingletonWW getInstance(){
if(instance==null){
instance = new SingletonWW();
}
return instance;
}
}
这种写法和第一种的区别在于:实例并没有直接实例化,而是在静态工厂方法被调用的时候才进行的,而且对静态工厂方法使用了同步化,以处理多线程并发的环境。
这两种写法还有两个非常有意思的名字:第一种称为饿汉式单例,第二种称为懒汉式单例。
饿汉式单例在自己被加载时就将自己实例化,如果从资源利用效率角度来讲,比懒汉式单例类稍差些。但是从速度和反应时间角度来讲,则比懒汉式要稍好些。
但是遗憾的是:懒汉式单例类也不能被继承。
我们克服前两种单例类不能被继承的缺点,我们可以使用另外一种特殊化的单例模式,它被称为单例注册表。
package spring;
import java.util.HashMap;
public class SingletonWW {
private static HashMap registry = new HashMap();
public SingletonWW(){}
//静态工厂方法
public synchronized static SingletonWW getInstance(String name){
if(name != null) {
if(registry.get(name) == null) {
try {
registry.put(name, Class.forName(name).newInstance());
} catch(Exception ex) {
ex.printStackTrace();
}
} else {
return (SingletonWW) registry.get(name);
}
}
return null;
}
}
| <bean id="date" class="java.util.Date"/> |
| <bean id="date" class="java.util.Date" scope="singleton"/> (仅为Spring2.0支持) |
| <bean id="date" class="java.util.Date" singleton="true"/> |
| <bean id="date" class="java.util.Date" scope="prototype"/> |
public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{
/**
* 充当了Bean实例的缓存,实现方式和单例注册表相同
*/
private final Map singletonCache=new HashMap();
public Object getBean(String name)throws BeansException{
return getBean(name,null,null);
}
...
public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{
//对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码)
String beanName=transformedBeanName(name);
Object bean=null;
//手工检测单例注册表
Object sharedInstance=null;
//使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高
synchronized(this.singletonCache){
sharedInstance=this.singletonCache.get(beanName);
}
if(sharedInstance!=null){
...
//返回合适的缓存Bean实例
bean=getObjectForSharedInstance(name,sharedInstance);
}else{
...
//取得Bean的定义
RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false);
...
//根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关
//<bean id="date" class="java.util.Date" scope="singleton"/>
//如果是单例,做如下处理
if(mergedBeanDefinition.isSingleton()){
synchronized(this.singletonCache){
//再次检测单例注册表
sharedInstance=this.singletonCache.get(beanName);
if(sharedInstance==null){
...
try {
//真正创建Bean实例
sharedInstance=createBean(beanName,mergedBeanDefinition,args);
//向单例注册表注册Bean实例
addSingleton(beanName,sharedInstance);
}catch (Exception ex) {
...
}finally{
...
}
}
}
bean=getObjectForSharedInstance(name,sharedInstance);
}
//如果是非单例,即prototpye,每次都要新创建一个Bean实例
//<bean id="date" class="java.util.Date" scope="prototype"/>
else{
bean=createBean(beanName,mergedBeanDefinition,args);
}
}
...
return bean;
}
}
刚才的源码中,大家真正要记住的是Spring对bean实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是HashMap对象,如果配置文件中的配置信息不要求使用单例,Spring会采用新建实例的方式返回对象实例
如果还对 Spring 的AOP、IOC、ORM感兴趣的,可以看看我写的轻量级框架 swift-framework 框架,简单易懂,而且可用。包含了Spring 中的基本核心功能。
Spring的单例模式底层实现学习笔记的更多相关文章
- Spring实战第四章学习笔记————面向切面的Spring
Spring实战第四章学习笔记----面向切面的Spring 什么是面向切面的编程 我们把影响应用多处的功能描述为横切关注点.比如安全就是一个横切关注点,应用中许多方法都会涉及安全规则.而切面可以帮我 ...
- Spring实战第六章学习笔记————渲染Web视图
Spring实战第六章学习笔记----渲染Web视图 理解视图解析 在之前所编写的控制器方法都没有直接产生浏览器所需的HTML.这些方法只是将一些数据传入到模型中然后再将模型传递给一个用来渲染的视图. ...
- Spring实战第五章学习笔记————构建Spring Web应用程序
Spring实战第五章学习笔记----构建Spring Web应用程序 Spring MVC基于模型-视图-控制器(Model-View-Controller)模式实现,它能够构建像Spring框架那 ...
- Spring入门IOC和AOP学习笔记
Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理.创建所有的Java对象,这些Java对象被称为Bean. Spring容器管理容 ...
- (转)Spring的单例模式底层实现
单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例. 单例模式有以下的特点: ① 单例类只能有一个实例 ② 单例类必须自己创建自己的唯一实例 ③ 单例类 ...
- Spring WebFlux 响应式编程学习笔记(一)
各位Javaer们,大家都在用SpringMVC吧?当我们不亦乐乎的用着SpringMVC框架的时候,Spring5.x又悄(da)无(zhang)声(qi)息(gu)的推出了Spring WebFl ...
- Spring Cloud 微服务架构学习笔记与示例
本文示例基于Spring Boot 1.5.x实现,如对Spring Boot不熟悉,可以先学习我的这一篇:<Spring Boot 1.5.x 基础学习示例>.关于微服务基本概念不了解的 ...
- spring boot 尚桂谷学习笔记04 ---Web开始
------web开发------ 1.创建spring boot 应用 选中我们需要的模块 2.spring boot 已经默认将这些场景配置好了 @EnableAutoConfiguration ...
- spring AOP面向切面编程学习笔记
一.面向切面编程简介: 在调用某些类的方法时,要在方法执行前或后进行预处理或后处理:预处理或后处理的操作被封装在另一个类中.如图中,UserService类在执行addUser()或updateUse ...
随机推荐
- Linux开启和关闭防火墙
一.即时生效,重启后失效: 1.启动:service iptables start 2.关闭:service iptables stop 二.重启后永久生效: 1.启动:chkconfig iptab ...
- Java 的布局管理器GridBagLayout的使用方法【图文说明】
https://www.cnblogs.com/taoweiji/archive/2012/12/14/2818787.html GridBagLayout是java里面最重要的布局管理器之一,可以做 ...
- 【转】Java学习---10个测试框架介绍
[原文]https://www.toutiao.com/i6594302925458113027/ JAVA 程序员需要用到 10 个测试框架和库 Java 程序员需要用到十大单元测试和自动化集成测试 ...
- yum安装某个包出现冲突的情况
yum安装是非常方便的,可以自动解决依赖问题,但是有时候我们安装包会出现冲突,这个时候我们就要查找是哪些包与哪些包出现冲突,然后再针对性的解决问题. 一般来说起冲突的包会报出来,主要为两点 1.包与包 ...
- SAP业务蓝图设计的一些想法
SAP蓝图设计是面向业务流程的,目前国内很多软件公司在做蓝图设计(概要设计)都是面向功能的,而对于用户来说,需要的不是一个个功能点,而是要实现具体的业务.功能点是一个点,而业务流程是一条线.是在梳理业 ...
- Docker容器学习与分享07
Docker容器网络 在分享06中学完了bridge网络,接着学习none网络和host网络. Docker在安装时会在host上默认创建三个网络,分别是bridge.host.null. [root ...
- selenium3 浏览器驱动下载及验证
下载浏览器驱动 当selenium升级到3.0之后,对不同的浏览器驱动进行了规范.如果想使用selenium驱动不同的浏览器,必须单独下载并设置不同的浏览器驱动. 各浏览器下载地址: Firefox浏 ...
- 在学习前端的路上,立下一个Flag
今天开始百度前端学习,以此为证
- 动态显示checkbox选中条数
<script> $('input[type=checkbox]').click( function () { $('span#cheak_len').empty(); var len = ...
- 使用 rem 作为单位使页面自适应设备宽度
一.新建 rem.js 文件,代码如下: export default function () { document.documentElement.style.fontSize = document ...