找回密码
 立即注册
首页 业界区 业界 技术面:Spring (bean的生命周期、创建方式、注入方式、 ...

技术面:Spring (bean的生命周期、创建方式、注入方式、作用域)

僭墙覆 昨天 21:31
Spring Bean的生命周期是什么样的?

在Spring容器里一个Bean的从创建到销毁一般都是经历了以下几个阶段:
定义阶段(Bean元信息配置)=>实例化阶段(创建Bean对象)=>初始化阶段(执行初始化逻辑)=>使用阶段(Bean可用)=>销毁阶段(释放资源)
1.png

定义阶段(BeanDefinition解析)

Spring通过配置(XML、注解、Java配置)解析Bean的元数据,生成BeanDefinition对象
BeanDefinition存储了Bean的类名、作用域(scope)、依赖项(depends-on)、初始化方法、销毁方法等元数据。
所有BeanDefinition存储在容器的BeanDefinitionMap(一个HashMap)中,键为Bean名称,值为BeanDefinition对象。
解析器:

  • XML配置:XmlBeanDefinitionReader解析标签。
  • 注解配置:ClassPathBeanDefinitionScanner扫描@Component等注解。
  • Java配置:ConfigurationClassPostProcessor解析@Bean方法。
实例化阶段(创建Bean实例)

根据BeanDefinition通过反射或工厂方法创建Bean实例(对象),但此时属性未注入
默认通过无参构造方法实例化(若未指定,Spring会强制要求无参构造)。
在AbstractAutowireCapableBeanFactory类中的createBeanInstance方法中实现。
属性值填充(依赖注入)

为Bean的属性设置值或注入依赖

  • 通过@Autowired、@Value、XML的等方式注入属性。
  • 若注入的依赖是其他Bean,会递归触发依赖Bean的生命周期。
  • 循环依赖问题:在属性注入阶段处理循环依赖(通过三级缓存解决)。
在AbstractAutowireCapableBeanFactory的populateBean方法中处理。
Aware接口回调设置

若Bean实现了特定Aware接口,Spring会回调对应方法,注入容器相关对象

  • BeanNameAware:注入Bean在容器中的名称(setBeanName(String beanName))。
  • BeanFactoryAware:注入当前Bean所在的BeanFactory(setBeanFactory(BeanFactory beanFactory))。
  • ApplicationContextAware:若容器是ApplicationContext,注入应用上下文(setApplicationContext(ApplicationContext applicationContext))。
在AbstractAutowireCapableBeanFactory的initializeBean方法中调用。
BeanPostProcessor前置处理

在Bean初始化前,允许自定义BeanPostProcessor对Bean实例进行处理。
主要是调用BeanPostProcessor的postProcessBeforeInitialization方法。
常见的实现类

  • ApplicationContextAwareProcessor:处理ApplicationContextAware接口。
  • InitDestroyAnnotationBeanPostProcessor:处理@PostConstruct注解。
由AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsBeforeInitialization方法执行。
InitializingBean处理以及自定义init-method处理

执行Bean的初始化逻辑。
InitializingBean处理,在所有Bean属性设置完成后进行初始化操作。如果Bean实现了InitializingBean接口,InitializingBean的afterPropertiesSet方法会被调用。
自定义init-method处理,如果Bean在配置文件中定义了初始化方法那么该方法会被调用。
例如:通过XML配置init-method或Java配置@Bean(initMethod="xxx")。
在AbstractAutowireCapableBeanFactory的invokeInitMethods方法中调用
BeanPostProcessor后置处理

在Bean初始化后,允许自定义BeanPostProcessor对Bean实例进行处理。
BeanPostProcessor的postProcessAfterInitialization方法会被调用。
常见用途:AOP代理(如AbstractAutoProxyCreator在此阶段为目标对象创建代理)
由AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsAfterInitialization方法执行
注册DisposableBean回调

如果Bean实现了DisposableBean接口或在Bean定义中指定了自定义的销毁方法,Spring容器会为这些Bean注册一个销毁回调,确保在容器关闭时能够正确地清理资源。
在AbstractAutowireCapableBeanFactory类中的registerDisposableBeanlfNecessary方法中实现
Bean使用阶段

Bean已完全初始化,可被应用程序使用。通过依赖注入获取Bean实例(如@Autowired或ApplicationContext.getBean())。
此阶段Bean处于“可用”状态,直到容器关闭。
Bean销毁阶段

容器关闭时,释放Bean资源。
主要步骤:

  • 接口回调:若Bean实现了DisposableBean,调用destroy方法。
  • 注解:若方法标注了@PreDestroy,Spring会调用该方法。
  • 自定义销毁方法:通过XML配置destroy-method或Java配置@Bean(destroyMethod="xxx")。
  • 资源释放:如关闭数据库连接、释放文件句柄等。
在DisposableBeanAdapter的destroy方法中实现
总结

通过代码出处,可以观察到整个Bean的创建的过程都依赖于AbstractAutowireCapableBeanFactory这个类,而销毁主要依赖DisposableBeanAdapter这个类。
AbstractAutowireCapableBeanFactory 的入口处,doCreateBean的核心代码如下,其中包含了实例化、设置属性值、初始化Bean以及注册销毁回调的几个核心方法。
这里就不贴代码了,想更深入看细节的可以去看源码。
Spring中创建Bean的方式有哪些?

基于注解的自动扫描

通过注解标记类,并配合组件扫描实现自动注册。
常见的注解有
@Component, @Service, @Repository, @Controller(及其衍生注解)。
例如:当在类上添加@Component时,再在配置类或 XML 中启用组件扫描(@ComponentScan 或 )。这个类在服务启动时会自动被扫描到,然后注入到Spring容器。
  1. @Configuration
  2. @ComponentScan("com.jimoer.service")
  3. public class BeanConfig {
  4. }
复制代码
  1. @Service
  2. public class UserService {
  3.     public void hello() {
  4.         System.out.println("Hello from UserService");
  5.     }
  6. }
  7. @Component
  8. public class UserHandler {
  9.     public void hello() {
  10.         System.out.println("Hello from UserHandler");
  11.     }
  12. }
  13. @Repository
  14. public class UserRepository {
  15.     public void hello() {
  16.         System.out.println("Hello from UserRepository");
  17.     }
  18. }
  19. @Controller
  20. public class UserController {
  21.     public void hello() {
  22.         System.out.println("Hello from UserController");
  23.     }
  24. }
复制代码
使用@Configuration与@Bean 注解

通过 @Configuration 标注的配置类,显式定义 Bean 的创建逻辑。
适用于:需要精确控制 Bean 的初始化逻辑(如依赖其他 Bean 或复杂条件)。
  1. @Configuration
  2. public class AppConfig {
  3.     @Bean
  4.     public UserService userService() {
  5.         return new UserService();
  6.     }
  7. }
复制代码
XML 配置文件

通过 xml 的方式来定义 Bean。
在SpringBoot 流行以前,这种方式挺多的, SpringBoot 流行起来之后,这么用的越来越少了。
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
  4.     <bean id="userService" >
  5.        <property name="message" value="Hello Spring!" />
  6.     </bean>
  7. </beans>
复制代码
接下来,我们将Spring配置中注册这个自定义的作用域。
这可以通过ConfigurableBeanFactory.registerScope 方法实现。
  1. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  2. UserService userService = context.getBean("userService");
复制代码
此时在Bean定义中使用自定义的作用域的名称jimoer。
Spring 容器将会根据你的自定义逻辑来创建和管理这些 Bean。
  1. @Import({UserServiceImpl.class})
  2. @Configuration
  3. public class UserBeanConfiguration {
  4. }
复制代码
2.png

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册