面试题-Spring Bean的生命周期

Spring Bean 生命周期分为哪几个阶段

在这里插入图片描述

  1. 实例化:Spring 容器通过调用构造函数来创建 Bean 的实例。在这个阶段,Spring 还会根据配置文件或者注解来决定 Bean 的具体实现类。

  2. 填充属性:在 Bean 实例化之后,Spring 会将配置文件中定义的属性注入到 Bean 实例中。这些属性可以是简单的数据类型,也可以是其他 Bean 的引用,具体取决于 Bean 的定义和注解配置。

  3. 初始化

    • @PostConstruct 注解的方法:如果 Bean 类中有使用 @PostConstruct 注解的方法,Spring 会在填充属性之后调用这些方法。这个阶段通常用于 Bean 的初始化逻辑。
    • InitializingBean 接口:如果 Bean 实现了 InitializingBean 接口,Spring 会调用 afterPropertiesSet() 方法来进行初始化。
    • init-method 配置:在 XML 配置中,如果定义了 init-method,Spring 会在填充属性之后调用指定的方法进行初始化。
  4. 使用:在 Bean 完成初始化之后,Spring 容器就可以将其交给应用程序使用了。这个阶段是 Bean 的正常工作阶段。

  5. 销毁

    • @PreDestroy 注解的方法:如果 Bean 类中有使用 @PreDestroy 注解的方法,Spring 会在 Bean 销毁之前调用这些方法。这个阶段用于进行 Bean 的清理工作。
    • DisposableBean 接口:如果 Bean 实现了 DisposableBean 接口,Spring 会调用 destroy() 方法来进行销毁操作。
    • destroy-method 配置:在 XML 配置中,如果定义了 destroy-method,Spring 会在 Bean 销毁之前调用指定的方法进行清理。

Bean详细生命周期过程:
在这里插入图片描述


浅析Bean生命周期源码实现

以下是精简代码:

1.1 DefaultListableBeanFactory

DefaultListableBeanFactory是Spring的核心BeanFactory实现,它负责Bean的创建和管理。在这个类中,Bean实例化的过程主要通过getBean方法来触发。

public <T> T getBean(Class<T> requiredType) throws BeansException {
    return doGetBean(null, null, requiredType, false);
}

public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

在doGetBean方法中,Spring会检查Bean是否已经存在于缓存中。如果不存在,则会调用createBean方法进行实例化。

protected <T> T doGetBean(String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) {
    // 省略部分逻辑
    if (bean != null) {
        return (T) bean;
    }
    return (T) createBean(beanName, mbd, args);
}

1.2 createBean

createBean方法负责Bean的实际实例化过程。首先,Spring会使用反射创建Bean实例。

protected <T> T createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 省略部分逻辑
    BeanWrapper beanWrapper = createBeanWrapper(beanClass);
    Object beanInstance = beanWrapper.getWrappedInstance();
    return (T) beanInstance;
}

在这个方法中,createBeanWrapper会创建一个BeanWrapper实例,用于包装和操作Bean实例。

protected BeanWrapper createBeanWrapper(Object bean) {
    return new BeanWrapperImpl(bean);
}

2.1 populateBean

populateBean方法负责将Bean的依赖注入到实例中。它会读取BeanDefinition中的属性配置,并将这些属性值注入到Bean实例中。

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    PropertyValues pvs = mbd.getResolvedProps();
    if (pvs != null) {
        for (PropertyValue pv : pvs.getPropertyValues()) {
            bw.setPropertyValue(pv.getName(), pv.getValue());
        }
    }
}

3.1 initializeBean

初始化阶段主要由 AbstractAutowireCapableBeanFactory 类中的 initializeBean 方法负责。这个方法会在 DefaultListableBeanFactorycreateBean 方法中被调用。

在这个方法中,首先检查Bean是否实现了InitializingBean接口。如果实现了,则调用其afterPropertiesSet方法。afterPropertiesSet方法中可以包含一些自定义的初始化逻辑,例如检查必需的属性是否被正确设置等。

protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
    // 调用 InitializingBean 的 afterPropertiesSet 方法
    if (bean instanceof InitializingBean) {
        try {
            ((InitializingBean) bean).afterPropertiesSet();
        } catch (Exception ex) {
            throw new BeanInitializationException("Initialization of bean failed", ex);
        }
    }

    // 调用用户自定义的初始化方法
    String initMethodName = mbd.getInitMethodName();
    if (initMethodName != null) {
        invokeInitMethod(beanName, bean, mbd);
    }

    return bean;
}

3.2 invokeInitMethod

invokeInitMethod方法会通过反射调用用户定义的初始化方法。这些方法是通过RootBeanDefinition中的initMethodName属性指定的。

private void invokeInitMethod(String beanName, Object bean, RootBeanDefinition mbd) {
    String initMethodName = mbd.getInitMethodName();
    try {
        Method initMethod = bean.getClass().getMethod(initMethodName);
        initMethod.invoke(bean);
    } catch (Exception e) {
        throw new BeansException("Failed to invoke init method '" + initMethodName + "' on bean with name '" + beanName + "'", e);
    }
}

invokeInitMethod方法会通过反射查找并调用指定的初始化方法。这个方法通常用于执行一些特定的初始化操作,比如建立数据库连接等

3.3 applyBeanPostProcessorsBeforeInitialization

Spring会在Bean的初始化过程中扫描并执行@PostConstruct注解标记的方法。这一过程通常发生在AbstractAutowireCapableBeanFactory类的applyBeanPostProcessorsBeforeInitialization方法中。

protected Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        result = processor.postProcessBeforeInitialization(result, beanName);
        if (result == null) {
            return null;
        }
    }
    return result;
}

在invokeInitMethod方法之前,会调用@PostConstruct注解的方法。
在这里插入图片描述

5.1 destroyBean

destroyBean 方法在 Spring 的 AbstractAutowireCapableBeanFactory 类中定义。它的作用是执行 Bean 销毁前的处理,包括调用 DisposableBean 接口的 destroy 方法和用户自定义的销毁方法。

public void destroyBean(String beanName, Object bean) {
    // 调用DisposableBean的destroy方法
    if (bean instanceof DisposableBean) {
        try {
            ((DisposableBean) bean).destroy();
        } catch (Exception e) {
            throw new BeansException("Failed to invoke destroy method on bean with name '" + beanName + "'", e);
        }
    }
    
    // 调用用户自定义销毁方法
    String destroyMethodName = mbd.getDestroyMethodName();
    if (destroyMethodName != null) {
        invokeDestroyMethod(beanName, bean, mbd);
    }
}

5.2 invokeDestroyMethod

invokeDestroyMethod方法通过反射调用用户定义的销毁方法。

private void invokeDestroyMethod(String beanName, Object bean, String destroyMethodName) {
    try {
        Method destroyMethod = bean.getClass().getMethod(destroyMethodName);
        destroyMethod.invoke(bean);
    } catch (Exception ex) {
        throw new BeanCreationException("Failed to invoke destroy method '" + destroyMethodName + "' on bean with name '" + beanName + "'", ex);
    }
}

Spring Bean的后置处理器是什么?在项目中如何使用它?

Spring Bean 的后置处理器(BeanPostProcessor)是 Spring 框架中的一种机制,用于在 Bean 实例化和初始化的过程中插入自定义逻辑。它允许开发者在 Bean 实例化后、初始化前,和初始化后,执行额外的处理。

使用 BeanPostProcessor
要使用 BeanPostProcessor,需要实现 org.springframework.beans.BeanPostProcessor 接口,并重写 postProcessBeforeInitializationpostProcessAfterInitialization 方法。以下是如何在项目中使用它的步骤:

  1. 创建自定义的 BeanPostProcessor 实现:

    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class CustomBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在 Bean 初始化之前进行处理
        System.out.println("Before Initialization: " + beanName);
        return bean; // 返回处理后的 Bean
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在 Bean 初始化之后进行处理
        System.out.println("After Initialization: " + beanName);
        return bean; // 返回处理后的 Bean
    }
    
  2. 将自定义 BeanPostProcessor 注册到 Spring 容器中:

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class AppConfig {
    	@Bean
    	public CustomBeanPostProcessor customBeanPostProcessor() {
        	return new CustomBeanPostProcessor();
    	}
    }
    

应用场景

  • 动态修改 Bean:在 Bean 初始化后对其进行修改,例如为 Bean 添加额外的属性或功能。
  • 日志记录:记录 Bean 的创建和初始化过程,便于调试和监控。
    创建代理:使用 AOP 创建 Bean 的代理对象,以添加额外的功能如事务管理、安全控制等。

Spring Bean的生命周期中,哪些阶段可以介入自定义操作

初始化前

方法:

  • postProcessBeforeInitialization(由 BeanPostProcessor 提供)

应用: 在Bean初始化之前执行额外的处理,例如修改Bean的状态或属性,进行预处理操作。

初始化时

方法:

  • afterPropertiesSet(由 InitializingBean 接口提供)
  • @PostConstruct 注解方法
  • XML 配置中的 init-method 方法

应用: 在Bean的属性设置完成后,执行初始化逻辑,如设置默认值、进行资源准备或配置。

初始化后

方法:

  • postProcessAfterInitialization(由 BeanPostProcessor 提供)

应用: 在Bean初始化之后执行附加处理,例如创建代理对象、添加功能、日志记录等。

销毁前

方法:

  • destroy(由 DisposableBean 接口提供)
  • @PreDestroy 注解方法
  • XML 配置中的 destroy-method 方法

应用: 在Bean销毁之前进行清理操作,例如释放资源、保存状态或关闭连接等。


Spring Bean 的作用域都有哪些?如何控制 Bean 的生命周期?

  1. Singleton(单例)
    描述: 默认作用域。Spring容器中只创建一个Bean实例,并在整个容器中共享这个实例。
    生命周期: 从容器启动到容器关闭期间,Bean实例始终存在。
  2. Prototype(原型)
    描述: 每次请求都会创建一个新的Bean实例。每个实例都有独立的生命周期。
    生命周期: 每次获取Bean时,都会创建一个新的实例。Bean的生命周期从创建开始,到被垃圾回收时结束。
  3. Request(请求)
    描述: 每个HTTP请求都会创建一个新的Bean实例。Bean的生命周期与HTTP请求相对应。
    生命周期: 从每个HTTP请求开始到请求结束,每次请求都会创建一个新的Bean实例。
  4. Session(会话)
    描述: 每个HTTP会话创建一个新的Bean实例。Bean的生命周期与HTTP会话相对应。
    生命周期: 从每个HTTP会话开始到会话结束,每个会话都有一个独立的Bean实例。
  5. GlobalSession(全局会话)
    描述: 在Portlet环境中使用。每个全局会话创建一个新的Bean实例。
    生命周期: 适用于Portlet应用中的全局会话,每个全局会话有一个独立的Bean实例。

例如,配置一个原型作用域的 Bean:

<bean id="myBean" class="com.example.MyBean" scope="prototype"/>

或通过注解@scope 设置

此外,我们还可以自定义 Bean 的初始化和销毁方法,以在 Bean 作用域开始和结束时执行特定逻辑。可以通过 init-methoddestroy-method 属性来指定这些方法:

<bean id="myBean" class="com.example.MyBean" scope="prototype"
      init-method="start" destroy-method="end">
</bean>

Spring中的延迟初始化是什么,如何配置延迟初始化?

在Spring中,延迟初始化(Lazy Initialization)是一种延迟Bean创建的机制,即只有在实际需要Bean时才会创建它,而不是在容器启动时就立即创建。这可以提高应用程序的启动速度和资源利用率,特别是对于那些不常用的Bean。

延迟初始化的配置方式

  1. 通过 @Lazy 注解

    • 应用场景:在类级别或方法级别使用,表示当Bean首次被使用时才会被创建。
    • 配置方式:
      • 在类上:对整个Bean类应用延迟初始化。
      @Lazy
      @Component
      public class MyBean {
          // Bean实现
      }
      
      • 在方法上:对特定的Bean方法应用延迟初始化。
      @Configuration
      public class AppConfig {
          
          @Bean
          @Lazy
          public MyBean myBean() {
              return new MyBean();
          }
      }
      
  2. 在 XML 配置中

    • 应用场景:在传统的XML配置中配置延迟初始化。
    • 配置方式:
    <bean id="myBean" class="com.example.MyBean" lazy-init="true"/>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值