浅谈Spring Bean对象创建过程

一、引言

本文以BeanFactory为切入点,浅谈Spring是如何创建Bean的。

二、何为BeanFactory

当谈到Spring时,我们首先联想到的是IOC、AOP两大特性,这种高逼格的东西,让一些java初学者望而却步,但其实它本质上就是个"Bean容器"。而容器中的Bean对象就是由BeanFactory生产的,BeanFactory通过工厂模式实现对Bean对象的管理从而隐藏了对象的具体实现细节。下面我们看看BeanFactory是如何创建Bean的

三、实例化Bean对象

Bean在实例化之前,必须是在Bean容器启动之后。所以我们分两个阶段介绍:

  1. Bean容器的启动阶段;
  2. Bean对象实例化阶段;

启动阶段

  1. 首先SpringBoot会读取Bean的xml配置文件,或者扫描相关注解,转换成一个BeanDefinition对象,其中保存了该bean的各种信息:
  • beanClass: bean的class属性
  • scope:bean是否单例
  • abstractFlag: 该bean是否抽象
  • lazyInit: 是否延迟初始化
  • autowireMode:保存是否自动装配
  • dependencyCheck:保存是否坚持依赖
  • dependsOn:保存该bean依赖于哪些bean(这些bean必须在初始化时提前初始化)
  • constructorArgumentValues:保存通过构造函数注入的依赖
  • propertyValues:保存通过setter方法注入的依赖
  • factoryBeanName 和 factoryMethodName:用于factorybean,即工厂类型的bean
  • initMethodName 和 destroyMethodName:分别对应bean的init-method和destroy-method属性
  1. 然后通过BeanDefinitionRegistry将这些bean注册到BeanFactory中:
java 复制代码
public interface BeanDefinitionRegistry extends AliasRegistry {
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    boolean containsBeanDefinition(String beanName);
    String[] getBeanDefinitionNames();
    int getBeanDefinitionCount();
    boolean isBeanNameInUse(String beanName);
}

BeanFactory的实现类,需要实现BeanDefinitionRegistry 接口:

java 复制代码
@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    /** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
        @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        // ... ...       this.beanDefinitionMap.put(beanName, beanDefinition);
       // ... ...
    }

在这里BeanDefinition被注册到了 DefaultListableBeanFactory, 保存在它的一个ConcurrentHashMap中。

实例化阶段

实例化阶段主要是通过反射或者CGLIB对bean进行实例化,在这个阶段Spring又给我们暴露了很多的扩展点:

  1. 各种的Aware接口,比如 BeanFactoryAware,MessageSourceAware,ApplicationContextAware。
  2. BeanPostProcessor接口: 实现了 BeanPostProcessor 接口的bean,在实例化bean时Spring会帮我们调用接口中的方法:
    • 在 Bean 初始化前后进行额外处理:通过重写 BeanPostProcessor 接口的方法,可以在目标 Bean 的初始化方法(eg:InitializingBean的afterPropertiesSet)调用之前(postProcessBeforeInitialization)和之后(postProcessAfterInitialization)执行自定义的处理操作。
  3. InitializingBean接口:实现了InitializingBean接口的bean,在实例化bean时Spring会帮我们调用afterPropertiesSet方法。
  4. DisposableBean接口:实现了BeanPostProcessor接口的bean,在该bean死亡时Spring会帮我们调用destroy方法。

补充:注解@PostConstruct和 @PreDestroy 也能达到 InitializingBean接口 和 DisposableBean接口的效果。

四. 总结

spring容器接管了bean的实例化,不仅仅是通过依赖注入达到了松耦合的效果,同时给我们提供了各种的扩展接口,来在bean的生命周期的各个时期插入我们自己的代码:

0) BeanFactoryPostProcessor接口(在容器启动阶段)

1) 各种的Aware接口

2) BeanPostProcessor接口

3) InitializingBean接口(@PostConstruct, init-method)

4) DisposableBean接口(@PreDestroy, destory-method)

相关推荐
苍何1 小时前
DeepSeek的Super-agent 设计,和我们的工程实践
后端
Patrick_Wilson2 小时前
第一次读 Go 项目:从两个源码文件弄清 package、import 和 go.mod
后端·go·编程语言
Patrick_Wilson2 小时前
执行 go build . 后,Go 怎样找到代码并生成程序
后端·go·编程语言
用户6919026813392 小时前
Redis 2:Redis 在怎么处理harness记忆
后端
Patrick_Wilson2 小时前
Go 变量不赋值时,为什么也有值
后端·go·编程语言
Patrick_Wilson2 小时前
读 Go 项目里的命令:run、build、test 分别做了什么
后端·go·编程语言
程序猿乐锅3 小时前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
Flynn Liang4 小时前
Spring AI 上生产:限流熔断、密钥与成本治理、私有化/混合部署、降级与 Prompt 灰度架构全解
人工智能·spring·架构·高可用·springai·成本治理·生产架构
code2cat4 小时前
【随笔】连续批处理:长短请求怎样在迭代之间补位
java·人工智能·后端·大语言模型·vllm
Flynn Liang4 小时前
Spring AI 2.0 深度解析:ChatClient、Advisor 链与 MCP——Java 工程师的 AI 落地最优解
java·人工智能·spring·大模型·架构设计·spring ai