您的当前位置:首页正文

Spring bean的生命周期和作用域

2024-11-29 来源:个人技术集锦

一、Spring框架背景知识:

1、关键词:轻量级框架,IOC容器(控制反转),AOP(面向切面编程),事务支持

2、主要内容:

从下往上:Test→支持Junit测试

Core Container(Beans, Core, Context)→IOC

AOP, ASpects→ AOP

3、IOC(Inversion of Control)控制反转–依赖注入(Independency Injection)

3.1、IOC

对象由原来程序本身创建,变成了程序接受对象;

层和层解耦分离,没有直接依赖关系;

bean: java对象

控制的内容: 谁来控制对象的创建(传统的应用程序对象的创建是由程序本身控制的,使用spring之后,由spring创建对象)

反转:程序本身创建对象,变为程序被动接受spring创建的对象。

IOC的实现是通过IOC容器实现的–BeanFactory

IOC创建对象的方式:

3.2、依赖注入(Dependency Injection)

依赖:指bean对象的创建依赖于容器,Bean对象的依赖资源

注入:指bean对象依赖的资源由容器来设置和装配

Spring注入:

  1. 构造器注入
  2. setter注入

4、bean的自动装配

简化spring配置文件

4.1、Autowiring

  1. byName(set方法后面的名称)
  2. byType
  3. constructor

二、Bean的作用域

scope

description

singleton(Default)(默认)单例,整个容器(Spring bean容器)中只有一个对象实例
prototype原型,每次获取bean都产生一个新的对象
request每次HTTP请求时,新建一个对象,仅适用于基于Web的Spring ApplicationContext环境
session每次HTTP会话新建一个对象,仅适用于基于Web的Spring ApplicationContext环境
application一个ServletContext拥有一个对象,仅适用于基于Web的Spring ApplicationContext环境
websocket每次WebSocket新建一个对象,仅适用于基于Web的Spring ApplicationContext环境

1、Singleton

Spring中的默认作用域;

在创建起容器时就同时自动创建了bean的对象,不管是否使用,都存在,而且每次获取到的对象都是同一个对象;

可以通过指定lazy-init="true"来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean;

优点:减少了新生成实例的消耗,减少jvm垃圾回收,可以快速获取到Bean

缺点:线程不安全

当看到这里的时候,很显然,会有一个疑问,既然Spring所有的bean默认都是单例的,那么是怎么保证线程安全的呢?

根据《深入理解JVM虚拟机》2.2.2节Java虚拟机栈

每个方法被执行的时候,Java虚拟机都 会同步创建一个栈帧[1](Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

每次执行方法时,都有自己的栈帧,这是线程隔离的;因此对于所有无状态单例都是线程安全的。

无状态:不会保存数据

有状态: 会保存数据

2、Prototype

Prototype作用域的bean在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。

在创建容器时并没有实例化,只有当我们获取bean的时候才会去创建一个对象,而且每次获取到的对象都不是同一个。

因此,对于有状态的bean应该使用Prototype,无状态的bean可以使用Singleton。

三、Bean的生命周期

Bean的生命周期概括:

  1. 实例化-Instantiation
  2. 属性赋值-Populate
  3. 初始化-Initialization
  4. 销毁-Destruction

 

以上总结的生命周期主要是 AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)类的doCreateBean方法

AbstractAutowireCapableBeanFactory.java 展开源码

/**
     * Actually create the specified bean. Pre-creation processing has already happened
     * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
     * <p>Differentiates between default bean instantiation, use of a
     * factory method, and autowiring a constructor.
     * @param beanName the name of the bean
     * @param mbd the merged bean definition for the bean
     * @param args explicit arguments to use for constructor or factory method invocation
     * @return a new instance of the bean
     * @throws BeanCreationException if the bean could not be created
     * @see #instantiateBean
     * @see #instantiateUsingFactoryMethod
     * @see #autowireConstructor
     */
    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
 
        // Instantiate the bean.实例化
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            // 
 
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
 
        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }
 
        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
 
        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
             // 属性填充 
            populateBean(beanName, mbd, instanceWrapper);
             // 初始化 
                 // 完成属性依赖注入后,进一步初始化Bean
                    // 具体进行了以下操作:
                    // 1.若实现了BeanNameAware, BeanClassLoaderAware,BeanFactoryAwareAware等接口,则注入相关对象
                    // 2.遍历后置处理器,调用实现的postProcessBeforeInitialization方法,
                    // 3.如果实现了initialzingBean,调用实现的 afterPropertiesSet()
                    // 4.如果配置了init-mothod,调用相应的init方法
                    // 5.遍历后置处理器,调用实现的postProcessAfterInitialization
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }
 
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }
 
        // Register bean as disposable.
        // 如果符合 bean 的销毁条件,则执行单例bean 的销毁工作
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }
 
        return exposedObject;
    }

initializeBean 展开源码

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            // 执行Aware
            invokeAwareMethods(beanName, bean);
        }
 
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化前BeanPostProcessors
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
 
        try {
            // 初始化
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化后BeanPostProcessors
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
 
        return wrappedBean;
    }

1、首先思考一个问题,既然说Spring大部分都是单例,只要不是懒加载的单例,在容器启动后就自动创建了,那是什么时候创建的?

在该方法上打断点,查看调用栈可以发现,main方法开始后,层层调用,在AbstractApplicationContext类的refresh()方法里面:

 

// Instantiate all remaining (non-lazy-init) singletons.

// 实例化非懒加载的单例bean

finishBeanFactoryInitialization(beanFactory);

然后调用到doCreateBean();

Demo实现测试:

Demo

package com.example.demo.Entity;

import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

/**

 * @Version 1.0

 * @Author LifeBean

 * @Date 2022/3/30 6:43 PM

 * @Description

 */

public class LifeBean implements InitializingBean {

    private String name;

    public LifeBean(){

        System.out.println("LifeBean()构造函数");

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        System.out.println("setName()" + name);

        this.name = name;

    }

    @Override

    public void afterPropertiesSet() throws Exception {

        System.out.println("this is after properties set");

    }

    public void init(){

        System.out.println("this is init of lifeBean");

    }

    public void destroy(){

        System.out.println("this is destory of lifeBean " + this);

    }

    @PostConstruct

    public void post() {

        System.out.println("this is post constructor of lifeBean");

    }

    @PreDestroy

    public void pre() {

        System.out.println("this is pre destroy of lifeBean");

    }

}

配置类

package com.example.demo.Config;

import com.example.demo.Entity.LifeBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

 * @Version 1.0

 * @Author LifeBeanConfig

 * @Date 2022/4/1 7:29 PM

 * @Description

 */

@Configuration

public class LifeBeanConfig {

    @Bean(initMethod = "init", destroyMethod = "destroy")

    LifeBean lifeBean() {

        LifeBean  lifeBean = new LifeBean();

        lifeBean.setName("testAnnotation");

        return lifeBean;

    }

}

测试代码

package com.example.demo;

import com.example.demo.Entity.LifeBean;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.ApplicationContext;

@SpringBootApplication

public class Demo2Application {

    public static void main(String[] args) {

       ApplicationContext applicationcontext = SpringApplication.run(Demo2Application.class, args);

        LifeBean life1 = (LifeBean) applicationcontext.getBean("lifeBean");

        System.out.println(life1.getName());

    }

}

运行测试代码,可以看到输出:

可以看到符合生命周期的轨迹。

以上是一个单例bean的生命周期,将bean的type改成prototype,可以发现当容器关闭时,作为prototype作用域的bean,predestroy方法和destroy方法都没有被调用,spring不对prototype bean的整个生命周期负责。

待解决的问题:

  1. 循环依赖

参考

1.

2.

 

显示全文