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

Spring Bean的生命周期是什么样的?

在Spring容器里一个Bean的从创建到销毁一般都是经历了以下几个阶段:
定义阶段(Bean元信息配置)=>实例化阶段(创建Bean对象)=>初始化阶段(执行初始化逻辑)=>使用阶段(Bean可用)=>销毁阶段(释放资源)
技术面:Spring (bean的生命周期、创建方式、注入方式、作用域)

定义阶段(BeanDefinition解析)

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

  • XML配置:XmlBeanDefinitionReader解析<bean>标签。
  • 注解配置:ClassPathBeanDefinitionScanner扫描@Component等注解。
  • Java配置:ConfigurationClassPostProcessor解析@Bean方法。

实例化阶段(创建Bean实例)

根据BeanDefinition通过反射或工厂方法创建Bean实例(对象),但此时属性未注入
默认通过无参构造方法实例化(若未指定,Spring会强制要求无参构造)。

AbstractAutowireCapableBeanFactory类中的createBeanInstance方法中实现。

属性值填充(依赖注入)

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

  • 通过@Autowired@ValueXML<property>等方式注入属性。
  • 若注入的依赖是其他Bean,会递归触发依赖Bean的生命周期。
  • 循环依赖问题:在属性注入阶段处理循环依赖(通过三级缓存解决)。

AbstractAutowireCapableBeanFactorypopulateBean方法中处理。

Aware接口回调设置

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

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

AbstractAutowireCapableBeanFactoryinitializeBean方法中调用。

BeanPostProcessor前置处理

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

  • ApplicationContextAwareProcessor:处理ApplicationContextAware接口。
  • InitDestroyAnnotationBeanPostProcessor:处理@PostConstruct注解。

AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsBeforeInitialization方法执行。

InitializingBean处理以及自定义init-method处理

执行Bean的初始化逻辑。
InitializingBean处理,在所有Bean属性设置完成后进行初始化操作。如果Bean实现了InitializingBean接口,InitializingBeanafterPropertiesSet方法会被调用。

自定义init-method处理,如果Bean在配置文件中定义了初始化方法那么该方法会被调用。
例如:通过XML配置init-method或Java配置@Bean(initMethod="xxx")。

AbstractAutowireCapableBeanFactoryinvokeInitMethods方法中调用

BeanPostProcessor后置处理

在Bean初始化后,允许自定义BeanPostProcessor对Bean实例进行处理。
BeanPostProcessorpostProcessAfterInitialization方法会被调用。

常见用途:AOP代理(如AbstractAutoProxyCreator在此阶段为目标对象创建代理)

AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsAfterInitialization方法执行

注册DisposableBean回调

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

AbstractAutowireCapableBeanFactory类中的registerDisposableBeanlfNecessary方法中实现

Bean使用阶段

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

Bean销毁阶段

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

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

DisposableBeanAdapterdestroy方法中实现

总结

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

Spring中创建Bean的方式有哪些?

基于注解的自动扫描

通过注解标记类,并配合组件扫描实现自动注册。
常见的注解有
@Component, @Service, @Repository, @Controller(及其衍生注解)。

例如:当在类上添加@Component时,再在配置类或 XML 中启用组件扫描(@ComponentScan<context:component-scan>)。这个类在服务启动时会自动被扫描到,然后注入到Spring容器。

@Configuration @ComponentScan("com.jimoer.service") public class BeanConfig {  } 
@Service public class UserService {     public void hello() {         System.out.println("Hello from UserService");     } }  @Component public class UserHandler {     public void hello() {         System.out.println("Hello from UserHandler");     } }  @Repository public class UserRepository {     public void hello() {         System.out.println("Hello from UserRepository");     } }  @Controller public class UserController {     public void hello() {         System.out.println("Hello from UserController");     } } 

使用@Configuration与@Bean 注解

通过 @Configuration 标注的配置类,显式定义 Bean 的创建逻辑。
适用于:需要精确控制 Bean 的初始化逻辑(如依赖其他 Bean 或复杂条件)。

@Configuration public class AppConfig {     @Bean     public UserService userService() {         return new UserService();     } } 

XML 配置文件

通过 xml 的方式来定义 Bean。
在SpringBoot 流行以前,这种方式挺多的, SpringBoot 流行起来之后,这么用的越来越少了。

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"     <bean id="userService" class="com.jimoer.demo.UserServiceImpl">        <property name="message" value="Hello Spring!" />     </bean> </beans> 
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = context.getBean("userService"); 

更适用于遗留项目或需要与非注解配置兼容的场景。

使用@Import注解

@Import注解的作用是快速导入某一个或多个类,使这些类能够被Spring加载到IOC容器中进行管理。
让类被Spring 的 IOC 容器管理,这不也是创建 Bean 么,因此,这种方式也可以算是创建Bean的一种方式。

@Import({UserServiceImpl.class}) @Configuration public class UserBeanConfiguration { } 

自定义注解

通过自定义一种注解,然后在 Spring 应用启动过程中,通过自定义的 BeanDefinitionRegistryPostProcessorBeanfactoryPostProcessor 来扫描配置的包路径,识别出带有自定义注解的类。
这些处理器解析注解中的属性(如接口类、版本号、超时时间等),并基于这些信息创建 Spring的 BeanDefinition
例如:Dubbo框架使用的@DubboService注解

@DubboService("version=1.0.0") public class UserServiceImpl implements UserFacadeService {  } 

动态注册(运行时注册)

在运行时通过 BeanDefinitionRegistry 动态注册 Bean。

// 获取 BeanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();  // 定义 Bean 的元数据 GenericBeanDefinition userDefinition = new GenericBeanDefinition(); userDefinition.setBeanClass(UserService.class);  // 注册 Bean beanFactory.registerBeanDefinition("userService", userDefinition); 

适用于:根据运行时条件动态生成 Bean(如插件化系统、动态配置)。

Spring Bean的注入方式有哪些?

使用@Autowired注解

@Autowired注解是Spring框架提供的一个注解,支持多种方式自动将Spring的bean注入到其他Bean中。

字段注入

@Component public class JimoerUserService {     @Autowired     private UserRepository userRepository; } 

构造方法注入

@Component public class JimoerUserService {     private final UserRepository userRepository;      // Spring 4.3+ 可省略 @Autowired(单构造器)     @Autowired     public JimoerUserService(UserRepository userRepository) {         this.userRepository = userRepository;     } } 

setter注入

@Component public class JimoerUserService {     private UserRepository userRepository;      @Autowired     public void setUserRepository(UserRepository userRepository) {         this.userRepository = userRepository;     } } 

使用@Resource和@Inject注解

除了Spring提供的注解,JDK也提供了可以互相注入Bean的注解,有@Resource@Inject

@Component public class JimoerUserService {     @Resource     private UserRepository userRepository; }  @Component public class JiomerUserService {     @Inject     private UserRepository userRepository; } 

使用XML配置注入

如何不使用注解注入,还可以使用XML文件的配置进行Bean的互相注入。

<bean id="userRepository" class="com.jimoer.UserRepository"/> <!-- 构造方法注入 --> <bean id="userService" class="com.jiomer.UserService">     <constructor-arg ref="userRepository"/> </bean> <!-- 字段注入 --> <bean id="jimoerUserService" class="com.jiomer.JimoerUserService">     <property name="userRepository" ref="userRepository"/> </bean> 

构造方法自动注入

其实从 Spring 4.3 开始,除非一个类中声明了至少两个构造函数,否则不需要用 @Autowired 标注构造函数,这个构造函数也能直接注入 Bean。

@Component public class JimoerUserService { 	private UserRepository userRepository; 	public JimoerUserService(UserRepository userRepository){ 		this.userRepository=userRepository; 	} } 

Spring Bean的作用域有哪些?

Spring的Bean的作用域,就是指这个Bean在哪个范围内可以被使用。
不同的作用域决定了Bean的创建管理和销毁的方式。

常见的作用域有SingletonPrototypeRequestSessionApplication这五种。
在代码中,可以在定义一个Bean的时候,通过@Scope 注解来指定他的作用域。

如果没有指定Bean的作用域,默认是Singleton(单例)。

Singleton(单例)

  • 周期:Spring 容器启动时创建实例,容器关闭时销毁。
  • 作用域:每个Spring IOC容器,只创建一个Bean实例。
  • 适用于:无状态服务(如工具类、缓存管理器、数据库连接池)。
  • 线程安全:需注意,若 Bean 有可变状态(即Bean中存在线程共享变量),需通过同步机制或线程安全集合处理。
  • 配置方式:
@Component // 默认即为 singleton public class SingletonBean { } 

Propertype(原型)

  • 周期:每次调用 getBean() 或注入时创建新实例,容器不负责销毁。
  • 适用于:有状态 Bean(如用户会话数据、临时对象)。
  • 线程安全:实例独立,避免线程安全问题。
  • 配置方式:
@Component @Scope("prototype") public class PrototypeBean { } 

Request(HTTP 请求)

  • 周期:每个 HTTP 请求创建一个实例,请求结束后销毁。
  • 适用于:Web 应用中请求级别的数据共享(如请求日志、上下文信息)。

仅适用于 Web 应用环境。

  • 配置方式:
@Component @Scope("request") public class RequestBean { } 

Session(HTTP 会话)

  • 周期:每个用户会话(HttpSession)创建一个实例,会话结束时销毁。
  • 适用于:用户会话数据(如购物车、用户偏好设置)。

仅适用于 Web 应用环境。

  • 配置方式:
@Component @Scope("session") public class SessionBean { } 

Application(应用)

  • 周期:Web 应用启动时创建实例,应用关闭时销毁。
  • 适用于:全局配置或共享资源(如应用级缓存、配置信息)。类似 singleton,但绑定到 ServletContext

仅适用于 Web 环境

  • 配置方式:
@Component @Scope("application") public class ApplicationBean { } 

Websocket(WebSocket 会话)

  • 周期:WebSocket 连接建立时创建实例,连接关闭时销毁。
  • 适用于:WebSocket 会话上下文数据(如实时通信状态)。

仅适用于 WebSocket 应用。

  • 配置方式:
@Component @Scope("websocket") public class WebSocketBean { } 

自定义作用域

一般情况下,在开发过程中,都是使用Singleton作用域,有时候也会用Propertype,其他几个用的都不多。但是除了上面列举的6个Spring提供作用域以外,还可以自己定义Bean作用域。

自定义一个Spring Bean的作用域,需要实现org.springframework.beans.factory.config.Scope接口,主要是实现如下几个方法来管理Bean的生命周期。

package org.springframework.beans.factory.config;  import org.springframework.beans.factory.ObjectFactory;  public interface Scope {     Object get(String var1, ObjectFactory<?> var2);      Object remove(String var1);      void registerDestructionCallback(String var1, Runnable var2);      Object resolveContextualObject(String var1);      String getConversationId(); } 

自定义一个类,然后实现Scope接口,来实现我们自己的Bean作用域。

public class JimoerScope implements Scope{     @Override     public Object get(String s, ObjectFactory<?> objectFactory) {         // 获取Bean的逻辑         return objectFactory.getObject();     }      @Override     public Object remove(String s) {         // 移除Bean的逻辑         return null;     }      @Override     public void registerDestructionCallback(String s, Runnable runnable) {         // 注册Bean销毁时的回调     }      @Override     public Object resolveContextualObject(String s) {         // 解析上下文         return null;     }      @Override     public String getConversationId() {         // 获取会话ID         return "";     } } 

接下来,我们将Spring配置中注册这个自定义的作用域。
这可以通过ConfigurableBeanFactory.registerScope 方法实现。

import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;  @Configuration public class AppConfig {      @Bean     public JimoerScope jimoerScope(ConfigurableBeanFactory beanFactory) {         JimoerScope jimoerScope = new JimoerScope();         beanFactory.registerScope("jimoer", jimoerScope);         return jimoerScope;     }  } 

此时在Bean定义中使用自定义的作用域的名称jimoer
Spring 容器将会根据你的自定义逻辑来创建和管理这些 Bean。

@Component @Scope("jimoer") public class CustomerScopeTest { } 

发表评论

评论已关闭。

相关文章