千家信息网

Spring Ioc中各个scope的Bean是怎么创建的

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,这篇文章主要讲解了"Spring Ioc中各个scope的Bean是怎么创建的",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Ioc中各个
千家信息网最后更新 2025年02月01日Spring Ioc中各个scope的Bean是怎么创建的

这篇文章主要讲解了"Spring Ioc中各个scope的Bean是怎么创建的",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Ioc中各个scope的Bean是怎么创建的"吧!


一、singleton

代码:

// 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.javapublic 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实例

  • 后置处理

  • 加入缓存

1.1、加载前置处理

beforeSingletonCreation(beanName)是个标记方法,我们来看代码:

// 用于添加标志,当前 bean 正处于创建中        protected void beforeSingletonCreation(String beanName) {                if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {                        //添加失败,抛出异常                        throw new BeanCurrentlyInCreationException(beanName);                }        }

把 beanName 添加到 singletonsCurrentlyInCreationmap中,用来表示该单例bean正在创建,如果添加失败,抛出异常。

1.2、获取Bean实例

通过createBean(beanName)方法返回的 singletonFactory 获取Bean。

1.3、后置处理

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是否已经在创建中。

1.4、加入缓存

直接看代码:

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 属性,已经注册的单例缓存。

二、Prototype

代码:

        //创建多例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.javaprivate final ThreadLocal> threadScope =                        new NamedThreadLocal>("SimpleThreadScope") {                                @Override                                protected Map initialValue() {                                        return new HashMap<>();                                }                        };        //获取bean的实例        @Override        public Object get(String name, ObjectFactory objectFactory) {                // 获取 scope 缓存                Map 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 Ioc中各个scope的Bean是怎么创建的"的内容了,经过本文的学习后,相信大家对Spring Ioc中各个scope的Bean是怎么创建的这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0