在Spring中Bean有许多不同的作用域,例如:singleton、prototype、request等等,本篇文章就来分析一下各个scope的Bean是怎么创建的
代码:
// Create bean instance. //创建单例Bean if (mbd.isSingleton()) { //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象 sharedInstance = getSingleton(beanName, () -> { try { //创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. //显式地从容器单例模式Bean缓存中清除实例对象 destroySingleton(beanName); throw ex; } }); //获取给定Bean的实例对象 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } 复制代码
这里使用了匿名内部类,先通过 createBean(beanName, mbd, args)
方法获取一个 ObjectFactory
把 ObjectFactory 作为参数传入 getSingleton(beanName,objectFactory)
方法
使用 getSingleton(beanName,objectFactory) 方法返回的 sharedInstance 作为参数传入 getObjectForBeanInstance(sharedInstance, name, beanName, mbd)
来回去最终的Bean实例(详情见 Spring Ioc 之 Bean的加载(一) )
createBean(beanName, mbd, args)
方法比较复杂,在之后的文章中会详细分析,这里就先略过,直接看 getSingleton(beanName,objectFactory)
方法。
// DefaultSingletonBeanRegistry.java public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); //全局加锁 synchronized (this.singletonObjects) { // 从缓存中获取单例bean // 因为 singleton 模式其实就是复用已经创建的 bean 所以这步骤必须检查 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //是否正在销毁该bean if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } // 加载前置处理 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 初始化 bean // 这个过程其实是调用 createBean() 方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. 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是在 singletonFactory.getObject()
方法实现的,而 singletonFactory 是由createBean()方法创建后回调的参数。
那么这段代码主要做的事情是什么呢?
尝试从缓存中获取单例Bean
如果已经加载了则直接返回,否则开始加载过程
加载前置处理
获取Bean实例
后置处理
加入缓存
beforeSingletonCreation(beanName)
是个标记方法,我们来看代码:
// 用于添加标志,当前 bean 正处于创建中 protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { //添加失败,抛出异常 throw new BeanCurrentlyInCreationException(beanName); } } 复制代码
把 beanName 添加到 singletonsCurrentlyInCreation
map中,用来表示该单例bean正在创建,如果添加失败,抛出异常。
通过 createBean(beanName)
方法返回的 singletonFactory 获取Bean。
afterSingletonCreation(beanName)
同样是个表示方法:
// 用于移除标记,当前 Bean 不处于创建中 protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { //移除失败,抛出异常 throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } } 复制代码
创建Bean之后移除创建标示。
前置处理和后置处理的这个创建标示,会在调用 isSingletonCurrentlyInCreation(String beanName)
时用到,该方法用来判断当前bean是否已经在创建中。
直接看代码:
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 操作。
【put】singletonObjects 属性,单例 bean 的缓存。
【remove】singletonFactories 属性,单例 bean Factory 的缓存。
【remove】earlySingletonObjects 属性,“早期”创建的单例 bean 的缓存。
【add】registeredSingletons 属性,已经注册的单例缓存。
代码:
//创建多例Bean else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. //原型模式(Prototype)是每次都会创建一个新的对象 Object prototypeInstance = null; try { //加载前置处理,默认的功能是注册当前创建的原型对象 beforePrototypeCreation(beanName); //创建指定Bean对象实例 prototypeInstance = createBean(beanName, mbd, args); } finally { //加载后置处理,默认的功能告诉IOC容器指定Bean的原型对象不再创建 afterPrototypeCreation(beanName); } //获取给定Bean的实例对象 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } 复制代码
原型模式很简单,直接创建一个新的实例就好了,不再从缓存中去获取。
beforePrototypeCreation(beanName)
前置处理,将当前bean标记为正在创建的原型。
afterPrototypeCreation(beanName)
后置处理,取消当前bean的正在创建标示。
调用 getObjectFrBeanInstance()
方法获取最终bean。(详情见 Spring Ioc 之 Bean的加载(一) )
//要创建的Bean既不是Singleton也不是Prototype //如:request、session、application等生命周期 else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); //Bean定义资源中没有配置生命周期范围,则Bean定义不合法 if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { //这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例 Object scopedInstance = scope.get(beanName, () -> { //前置处理 beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { //后置处理 afterPrototypeCreation(beanName); } }); //获取给定Bean的实例对象 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); } } 复制代码
分为以下几个步骤:
从Scope注解中获取scope名称
前置处理
createBean()
后置处理
scope.get()获取bean
getObjectForBeanInstance()方法获取Bean
核心流程与原型模式一样,只不过这里调用了scope.get()来获取bean。
Object get(String name, ObjectFactory<?> objectFactory); 复制代码
scope.get()是一个接口,它有多种实现类:
我们看一下spring自带的一个实现 SimpleThreadScope:
//SimpleThreadScope.java private final ThreadLocal<Map<String, Object>> threadScope = new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") { @Override protected Map<String, Object> initialValue() { return new HashMap<>(); } }; //获取bean的实例 @Override public Object get(String name, ObjectFactory<?> objectFactory) { // 获取 scope 缓存 Map<String, Object> scope = this.threadScope.get(); Object scopedObject = scope.get(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); // 加入缓存 scope.put(name, scopedObject); } return scopedObject; } 复制代码
其他scope的实现就不一一去看了,感兴趣的朋友可以自己看一下。
总结
上面的代码中有2个重要方法:
createBean(beanName, mbd, args)
getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)
这2个方法在3个代码分支中都用到了, createBean
下篇文章会详细分析, getObjectForBeanInstance
方法在 Spring Ioc 之 Bean的加载(一) 中已经分析过了。
这里再引用下《Spring 源码深度解析》对该方法的分析:
这个方法主要是验证以下我们得到的 bean 的正确性,其实就是检测当前 bean 是否是 FactoryBean 类型的 bean 。
如果是,那么需要调用该 bean 对应的 FactoryBean 实例的 getObject() 方法,作为返回值。
无论是从缓存中获得到的 bean 还是通过不同的 scope 策略加载的 bean 都只是最原始的 bean 状态,并不一定就是我们最终想要的 bean。
举个例子,假如我们需要对工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义 factory-method 方法中返回的 bean,而 getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法,就是完成这个工作的。
参考:
《Spring 源码深度解析》- 郝佳
芋道源码