在Spring中,Bean可以被定义为两种模式:prototype(原型)和singleton(单例)。
- singleton(单例)
只有一个共享的实例存在,所有对这个Bean的请求都会返回这个唯一的实例。 - prototype(原型)
对这个Bean的每次请求都会创建一个新的bean实例,类似于new。
Spring依赖注入Bean实例默认是单例的。
Spring的依赖注入(包括lazy-init方式)都是发生在 AbstractBeanFactory 的 getBean 里。
getBean 的 doGetBean 方法调用 getSingleton 进行Bean的创建。lazy-init方式(lazy-init=“false”),在用户向容器第一次索要Bean时进行调用;非lazy-init方式(lazy-init=“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实例的创建,从而造成重复创建的结果。