简介:
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
正文
单例模式分为3种:懒汉单例,饿汉单例,注册表单例
懒汉单例顾名思义,没有对象需要调用它的时候不去实例化,有人来向它要对象的时候再实例化对象,因为懒,比我还懒。
懒汉单例有线程安全和不安全两种写法,区别就在于静态工厂是否加同步。
public class Singleton {
private final static Singleton single = null;
private Singleton() {
}
//取消掉synchronized则线程不安全
public synchronized static Singleton getInstance() {
if(single==null) {
return new Singleton();
}else {
return single;
}
}
}
饿汉单例,就是它很饿,它的对象早早的就创建好了(懒汉是有人管它要了再创建),同上,也有线程安全和不安全之分。
public class Singleton {
private final static Singleton single = new Singleton();
private Singleton() {
}
//取消掉synchronized则线程不安全
public synchronized static Singleton getInstance() {
return single;
}
}
我们再用spring的时候知道,如果不去指定bean的scope="prototype",则其默认为singleton。那么spring源码又是怎么实现bean的单例的呢?
所谓注册表单例,就是将对象放到一个map中,key是bean的全类名,而value是bean的实例。
注册表单例解决了一个问题,即我们的饿汉和懒汉都是不能被继承的,我们这里将无参构造器设置为protected,那么我们的类就可以被继承了。
我们先写一个注册表单例:
public class Singleton {
private static final Map<String,Object> singletonCache = new HashMap<String,Object>();
private static final String single = "com.xuxiao.单例.注册表单例.Singleton";
static {
Singleton singleton = new Singleton();
singletonCache.put(singleton.getClass().getName(), singleton);
}
protected Singleton() {
}
public static Singleton getInstance() {
return getInstance("");
}
public static Singleton getInstance(String name) {
if(name=="") {
name=single;
}else if(singletonCache.get(name)==null){
try {
singletonCache.put(name, Class.forName(name).getConstructors()[0].newInstance());
} catch (SecurityException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return (Singleton) singletonCache.get(name);
}
}
可以看到,我们将创建单例对象的任务放到了静态代码块中,由于静态代码块的特性,保证了我们的单例bean可以不被final保护。
这里有个想说明的点,为什么我的静态工厂还要用反射来创建单例对象,我加了判断,如果我的map的value为空,我将创建bean填充。虽然map设置为private,但依然可以被反射获得并清空value。
接下来,我们来看spring源码中的为何默认创建bean为单例模式:
Spring的依赖注入(包括lazy-init方式)都是发生在 AbstractBeanFactory 的 getBean 里。 getBean 的 doGetBean 方法调用 getSingleton 进行bean的创建。lazy-init方式(lazy-init=“true”),在用户向容器第一次索要bean时进行调用;非lazy-init方式(lazy-init=“false”),在容器初始化时候进行调用。
我们首先来到AbstractBeanFactory 的 getBean
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}
doGetBean方法
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @param typeCheckOnly whether the instance is obtained for a type check,
* not for actual use
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
.....
getSingleton方法
@Override
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
从上面代码可以看到,spring依赖注入时,使用了 双重判断加锁 的单例模式。
首先从缓存singletonObjects(实际上是一个map)中获取bean实例,如果为null,对缓存singletonObjects加锁,然后再从缓存中获取bean,如果继续为null,就创建一个bean。
这样双重判断,能够避免在加锁的瞬间,有其他依赖注入引发bean实例的创建,从而造成重复创建的结果。
在这里Spring并没有使用私有构造方法来创建bean,而是通过 singletonFactory.getObject() 返回具体beanName对应的ObjectFactory来创建bean。
我们一路跟踪下去,发现实际上是调用了 AbstractAutowireCapableBeanFactory 的 doCreateBean 方法,返回了BeanWrapper包装并创建的bean实例。
(ObjectFactory主要检查是否有用户定义的BeanPostProcessor后处理内容,并在创建bean时进行处理,如果没有,就直接返回bean本身)
/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
instanceWrapper = createBeanInstance(beanName, mbd, args); 创建bean实例返回给BeanWrapper
addSingletonFactory 增加beanName和ObjectFactory的键值对应关系。
getEarlyBeanReference(beanName, mbd, bean); 获取bean的所有后处理器,并进行处理。如果是SmartInstantiationAwareBeanPostProcessor类型,就进行处理,如果没有相关处理内容,就返回默认的实现。
/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return null;
}
}
}
}
return exposedObject;
}