单例模式-Spring单例实现原理分析
Posted 彤哥博文
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式-Spring单例实现原理分析相关的知识,希望对你有一定的参考价值。
在Spring中,被@Scope注解修饰Bean默认是单例模式的,即只有一个实例对象,多次获取Bean会拿到同一个对象.
单例注册表
Spring采用单例注册表的特殊方式实现单例模式.首先自己写个单例注册表.我们可以通过Map缓存单例对象,实现单例注册表.值得注意的是,采用ConcurrentHashMap是出于线程安全的考虑.
/**
* @author tong.li
* @Description: 一个简单的单例实现,设计单例注册表
* @packagename: com.yimi.yts.learningpath
* @date 2018-03-27 10:04
*/
public class SingletonReg {
//构建采用ConcurrentHashMap,用于充当缓存注册表
private final static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(16);
// 静态代码块只加载执行一次
static {
// 实例化Bean
SingletonReg singletonReg = new SingletonReg();
//并注册到注册表中,key为类的完全限定名,value为实例化对象
singletonObjects.put(singletonReg.getClass().getName(),singletonReg);
}
/**
* 私有化构造方法,避免外部创建本类实例
*/
private SingletonReg() {}
/**
* 对外暴露获得该bean的方法,Spring框架一般会返回Object
* @return
*/
public static SingletonReg getInstance(String className) {
if (StringUtils.isEmpty(className)) {
return null;
}
//从注册表获取,如果没有直接创建
if (singletonObjects.get(className) == null) {
try {
//如果为空,通过反射进行实例化
singletonObjects.put(className, Class.forName(className).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
//从缓存表中回去,如果缓存命中直接返回
return (SingletonReg)singletonObjects.get(className);
}
}
同过以上单例实现,getInstance()方法通过传入类名进行判断,如果参数为null,那就无法获取bean,如果参数不为空,先从缓存注册表命中,如果命中就return掉,没有命中通过反射机制实例化一个return. 这样多次获得调用getInstance()方法都是获得同一个对象.测试如下:
public static void main(String[] args) {
/*
* 返回的都是同一个对象
* com.yimi.yts.learningpath.SingletonReg@3d82c5f3
* com.yimi.yts.learningpath.SingletonReg@3d82c5f3
*/
System.out.println( SingletonReg.getInstance("com.yimi.yts.learningpath.SingletonReg"));
System.out.println( SingletonReg.getInstance("com.yimi.yts.learningpath.SingletonReg"));
}
Spring源码分析
通过上述实现,Spring就是采用了这种单例注册表的特殊方式实现单例模式的.
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//对Bean的name进行处理,防止非法字符
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//从单例注册表中检查是否存在单例缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//省略部分代码...
// 返回缓存实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//省略代码...
try {
// ...忽略代码
// 单例模式,实例化bean,处理分支
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//原型魔兽,处理分支
else if (mbd.isPrototype()) {
//省略代码
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
}
其中中重要的代码是getSingleton()方法,下面深入分析该方法:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 通过 Map 实现单例注册表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// ...忽略代码
try {
singletonObject = singletonFactory.getObject();
}
catch (BeanCreationException ex) {
// ...忽略代码
}
finally {
// ...忽略代码
}
// 如果实例对象在不存在,我们注册到单例注册表中。
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
}
}
}
总结
综上述分析.我们可以得出:Spring对Bean实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是 ConcurrentHashMap对象。
以上是关于单例模式-Spring单例实现原理分析的主要内容,如果未能解决你的问题,请参考以下文章