在Spring中存在着不同的scope,默认是singleton,还有prototype、request等其他的scope,本篇文章将进行不同作用域实例创建的解析。
singleton作用域实例创建
Spring的scope默认为singleton,其初始化的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) {
destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
|
第一部分分析了从缓存中获取单例模式的bean,但是如果缓存中不存在,则需要创建对应的bean实例,这个过程由getSingleton()
实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { } beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
|
其实这个过程并没有真正创建bean,仅仅只是做了一部分准备和预处理步骤,真正获取单例bean的方法其实是由 singletonFactory.getObject()
这部分实现,而singletonFactory由回调方法产生。那么这个方法做了哪些准备呢?
- 获取同步锁,再次检查缓存是否存在对应的Bean,如果有则直接返回,没有则开始创建。
- 调用
beforeSingletonCreation()
记录单例bean处于正在创建,即前置处理。
- 调用参数传递的 ObjectFactory 的
getObject()
实例化 bean。
- 调用
afterSingletonCreation()
进行创建成功后的处理,删除bean正在创建的状态。
- 将结果记录并加入到单例Bean缓存中。
流程中涉及的三个方法 beforeSingletonCreation()
与 afterSingletonCreation()
在前面博客中分析过了,所以这里不再阐述了,我们看另外一个方法 addSingleton()
。
1 2 3 4 5 6 7 8
| protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
|
一个 put、一个 add、两个 remove。singletonObjects单例bean的缓存,singletonFactories存放创建Bean实例的ObjectFactory的缓存,earlySingletonObjects提前暴露的单例bean的缓存,registeredSingletons已经注册的单例缓存。
创建单例bean后,调用getObjectForBeanInstance()
进一步处理Bean,该方法已经在前面博客详细分析了。
上面就剩一个创建单例bean没有分析,这里先把剩下的流程分析完了,一起分析创建,因为后面的创建Bean是差不多的,只是条件的处理不同。
Prototype作用域实例创建
1 2 3 4 5 6 7 8 9 10 11 12
| else if (mbd.isPrototype()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); }
|
原型模式的初始化过程很简单:直接创建一个新的实例就可以了。过程如下:
- 调用
beforePrototypeCreation()
记录加载原型模式 bean 之前的加载状态,即前置处理。
- 调用
createBean()
创建一个 bean 实例对象。
- 调用
afterPrototypeCreation()
进行加载原型模式 bean 后的后置处理。
- 调用
getObjectForBeanInstance()
对创建的bean实例进一步的处理。
上面有一个点需要注意的,前面也说过,就是Prototype类型的bean创建的状态是存储到线程的私有变量中,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| protected void beforePrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String) { Set<String> beanNameSet = new HashSet<>(2); beanNameSet.add((String) curVal); beanNameSet.add(beanName); this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set<String> beanNameSet = (Set<String>) curVal; beanNameSet.add(beanName); } }
|
至于删除正在创建的状态,看了上面的代码相信你能够大概猜出来,这里就不具体讲解。
其他作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName); if (scope == null) { 。。。省略异常 } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); }catch (IllegalStateException ex) { }
|
核心流程和原型模式一样,只不过获取bean实例是由scope.get()
实现,后面会单独讲讲Spring中其他的Scope是如何保存Bean实例,毕竟创建过程是一样的。
对于上面三个模块,其中最重要的有两个方法,一个是 createBean()
、一个是 getObjectForBeanInstance()
。这两个方法在上面三个模块都有调用,createBean()
后续详细说明,getObjectForBeanInstance()
在前面博客中有详细讲解,这里再次阐述下(此段内容来自《Spring源码深度解析》):这个方法主要是验证我们得到的bean的正确性,其实就是检测当前bean是否是FactoryBean类型的 bean,如果是,那么需要调用该bean对应的FactoryBean实例的 getObject()
作为返回值。无论是从缓存中获得到的bean还是通过不同的scope策略加载的bean都只是最原始的bean 状态,并不一定就是我们最终想要的 bean。举个例子,加入我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义factory-method方法中返回的bean,而getObjectForBeanInstance()
就是完成这个工作的。