Spring中作用域有
a、默认值,singleton,表示单实例对象:
当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把 一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时 候,spring的IOC容器中只会存在一个该bean。
b、prototype,表示多实例对象:
prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。)
c、request
d、session
e、globalSession
1、实现scope的关键在于AbstractBeanFactory,首先看一下其结构
其父类DefaultSingletonBeanRegistry中有Map(singletonObjects)用来存放单例对象
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
//缓存单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
}
我们再看AbstractBeanFactory类
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@Override
public Object getBean(String name) throws BeansException {
//其中doGetBean是真正干活的
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取bean对象名
String beanName = transformedBeanName(name);
Object beanInstance;
//从singletonObjects缓存中看能否获取bean对象
Object sharedInstance = getSingleton(beanName);
//如果能够在singletonObjects中获取到对象,进入下面
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/*如果是FactoryBean类型的将会在该方法中被处理,并调用getObject
方法获取bean对象,因此能够保证FactoryBean是单例的且getObject
方法返回的一直是同一个对象才能保证getBean返回的对象是同一个*/
//详解:https://blog.csdn.net/xxg1993/article/details/100806923
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
……
……
/*跑到这里则说明前面的getSingleton方法从缓存中获取到单例对象,
意味着Spring工厂中还未创建该对象,
因此该方法中最终会调用createBean方法创建bean对象并缓存到单例集合中,
方便前面的getSingleton方法直接获取*/
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//如果是prototype,则直接创建对象,不缓存
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
……
……
}
总结:首先从缓存中看能否获取到bean对象,如果可以就说明是单例的,且存在的,可以直接获取;如果缓存中不存在,有两种情况:1)是单例的,但是是第一次使用,还未创建,后续进行单例对象的创建,并保存到缓存中;2)不是单例的,如果是prototype直接创建返回,不保存到缓存中。
补充: Spring中对象的创建时机
单例类(也是Spring bean对象默认的scope)
单例类(singleton),会在xml配置文件第一次被Application对象读取的时候,被创建并初始化。
原型类 (prototype)
只有在第一次被取出时,或者作为被取出对象的依赖对象时(会优先于被取出对象),被创建并初始化。
参考:1、https://blog.csdn.net/qq_27529917/article/details/78468731?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-1.highlightwordscore&spm=1001.2101.3001.4242.2
2、https://blog.csdn.net/Peelarmy/article/details/107366377?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.highlightwordscore&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.highlightwordscore