面试题-Spring Bean的生命周期
springbean生命周期
文章目录
Spring Bean 生命周期分为哪几个阶段
-
实例化:Spring 容器通过调用构造函数来创建 Bean 的实例。在这个阶段,Spring 还会根据配置文件或者注解来决定 Bean 的具体实现类。
-
填充属性:在 Bean 实例化之后,Spring 会将配置文件中定义的属性注入到 Bean 实例中。这些属性可以是简单的数据类型,也可以是其他 Bean 的引用,具体取决于 Bean 的定义和注解配置。
-
初始化:
- @PostConstruct 注解的方法:如果 Bean 类中有使用 @PostConstruct 注解的方法,Spring 会在填充属性之后调用这些方法。这个阶段通常用于 Bean 的初始化逻辑。
- InitializingBean 接口:如果 Bean 实现了 InitializingBean 接口,Spring 会调用 afterPropertiesSet() 方法来进行初始化。
- init-method 配置:在 XML 配置中,如果定义了 init-method,Spring 会在填充属性之后调用指定的方法进行初始化。
-
使用:在 Bean 完成初始化之后,Spring 容器就可以将其交给应用程序使用了。这个阶段是 Bean 的正常工作阶段。
-
销毁:
- @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 方法负责。这个方法会在 DefaultListableBeanFactory 的 createBean 方法中被调用。
在这个方法中,首先检查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 接口,并重写 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法。以下是如何在项目中使用它的步骤:
-
创建自定义的 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 }
-
将自定义 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 的生命周期?
- Singleton(单例)
描述: 默认作用域。Spring容器中只创建一个Bean实例,并在整个容器中共享这个实例。
生命周期: 从容器启动到容器关闭期间,Bean实例始终存在。 - Prototype(原型)
描述: 每次请求都会创建一个新的Bean实例。每个实例都有独立的生命周期。
生命周期: 每次获取Bean时,都会创建一个新的实例。Bean的生命周期从创建开始,到被垃圾回收时结束。 - Request(请求)
描述: 每个HTTP请求都会创建一个新的Bean实例。Bean的生命周期与HTTP请求相对应。
生命周期: 从每个HTTP请求开始到请求结束,每次请求都会创建一个新的Bean实例。 - Session(会话)
描述: 每个HTTP会话创建一个新的Bean实例。Bean的生命周期与HTTP会话相对应。
生命周期: 从每个HTTP会话开始到会话结束,每个会话都有一个独立的Bean实例。 - GlobalSession(全局会话)
描述: 在Portlet环境中使用。每个全局会话创建一个新的Bean实例。
生命周期: 适用于Portlet应用中的全局会话,每个全局会话有一个独立的Bean实例。
例如,配置一个原型作用域的 Bean:
<bean id="myBean" class="com.example.MyBean" scope="prototype"/>
或通过注解@scope 设置
此外,我们还可以自定义 Bean 的初始化和销毁方法,以在 Bean 作用域开始和结束时执行特定逻辑。可以通过 init-method 和 destroy-method 属性来指定这些方法:
<bean id="myBean" class="com.example.MyBean" scope="prototype"
init-method="start" destroy-method="end">
</bean>
Spring中的延迟初始化是什么,如何配置延迟初始化?
在Spring中,延迟初始化(Lazy Initialization)是一种延迟Bean创建的机制,即只有在实际需要Bean时才会创建它,而不是在容器启动时就立即创建。这可以提高应用程序的启动速度和资源利用率,特别是对于那些不常用的Bean。
延迟初始化的配置方式
-
通过 @Lazy 注解
- 应用场景:在类级别或方法级别使用,表示当Bean首次被使用时才会被创建。
- 配置方式:
- 在类上:对整个Bean类应用延迟初始化。
@Lazy @Component public class MyBean { // Bean实现 }
- 在方法上:对特定的Bean方法应用延迟初始化。
@Configuration public class AppConfig { @Bean @Lazy public MyBean myBean() { return new MyBean(); } }
-
在 XML 配置中
- 应用场景:在传统的XML配置中配置延迟初始化。
- 配置方式:
<bean id="myBean" class="com.example.MyBean" lazy-init="true"/>
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)