Spring Bean的生命周期

Spring Bean的生命周期,不仅涵盖每个阶段的细节,还包括Spring内部如何处理这些阶段,以及如何利用这些阶段来满足特定的需求。

1. Spring容器的启动

在Spring容器启动时,它会读取配置元数据(XML配置文件、Java配置类或注解),并开始实例化和初始化Bean。Spring容器的启动通常从调用ApplicationContext的实现类(如ClassPathXmlApplicationContextAnnotationConfigApplicationContext)的构造函数开始。在启动过程中,容器会执行一系列初始化操作,其中包括加载Bean定义、解析依赖关系以及初始化Bean。

2. 实例化 (Instantiation)

当Spring容器需要创建一个Bean时,它首先会根据配置信息调用相应的构造函数来实例化Bean。这个过程是通过BeanFactory来完成的。如果Bean定义中指定了工厂方法,那么Spring会调用该方法来创建Bean。

  • 无参构造器:这是最常见的实例化方式。
  • 工厂方法 :可以通过factory-beanfactory-method属性指定工厂Bean和工厂方法。
  • 静态工厂方法 :如果指定了class属性为静态工厂类,并且factory-method属性为静态方法,那么Spring会调用该静态方法来创建Bean。

3. 属性填充 (Populate Bean Properties)

一旦Bean被实例化,Spring就会开始填充Bean的属性。这个过程包括依赖注入和其他属性设置。

  • 依赖注入 :Spring根据Bean定义中的<property>标签或@Autowired注解来注入依赖。
  • 自动装配 :Spring支持通过autowire属性来自动装配依赖,或者使用@Autowired注解来实现自动装配。

4. 设置Bean名称 (Bean Name Aware)

如果Bean实现了BeanNameAware接口,Spring会在Bean的属性设置之后,但在初始化之前调用setBeanName方法,将Bean的名称传递给Bean。

public class MyBean implements BeanNameAware {
    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("BeanNameAware: Bean name is " + name);
    }
}

5. 设置Bean工厂 (Bean Factory Aware)

如果Bean实现了BeanFactoryAware接口,Spring会在属性设置之后,但在初始化之前调用setBeanFactory方法,将BeanFactory传递给Bean。

public class MyBean implements BeanFactoryAware {
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory factory) throws BeansException {
        this.beanFactory = factory;
        System.out.println("BeanFactoryAware: BeanFactory is set");
    }
}

6. 设置应用上下文 (Application Context Aware)

如果Bean实现了ApplicationContextAware接口,Spring会在属性设置之后,但在初始化之前调用setApplicationContext方法,将ApplicationContext传递给Bean。

public class MyBean implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.applicationContext = context;
        System.out.println("ApplicationContextAware: ApplicationContext is set");
    }
}

7. 预初始化处理 (Pre-Initialization Processing)

在Bean初始化之前,Spring会调用所有注册的BeanPostProcessorpostProcessBeforeInitialization方法。BeanPostProcessor接口允许我们在Bean初始化前后插入自定义逻辑。

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor: Before initialization of " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor: After initialization of " + beanName);
        return bean;
    }
}

8. 初始化 (Initialization)

  • InitializingBean接口 :如果Bean实现了InitializingBean接口,Spring会在属性设置之后调用afterPropertiesSet方法。

    public class MyBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
    System.out.println("InitializingBean: afterPropertiesSet method called");
    }
    }

  • init-method :如果在Bean定义中指定了init-method属性,Spring会调用该方法。

    <bean id="myBean" class="com.example.MyBean" init-method="customInit"/>
  • @PostConstruct注解 :如果Bean的方法上标注了@PostConstruct,Spring会在依赖注入完成后调用该方法。

    public class MyBean {
    @PostConstruct
    public void init() {
    System.out.println("@PostConstruct: Initialization method called");
    }
    }

9. 后初始化处理 (Post-Initialization Processing)

在Bean初始化之后,Spring会再次调用所有注册的BeanPostProcessorpostProcessAfterInitialization方法。

10. 使用 (Usage)

此时,Bean已经完全初始化,可以被应用程序使用。Spring容器会将Bean存储在单例池中(如果是单例作用域),以便后续请求时可以直接获取。

11. 销毁 (Destruction)

  • DisposableBean接口 :如果Bean实现了DisposableBean接口,Spring会在容器关闭时调用destroy方法。

    public class MyBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
    System.out.println("DisposableBean: destroy method called");
    }
    }

  • destroy-method :如果在Bean定义中指定了destroy-method属性,Spring会在容器关闭时调用该方法。

    <bean id="myBean" class="com.example.MyBean" destroy-method="customDestroy"/>
  • @PreDestroy注解 :如果Bean的方法上标注了@PreDestroy,Spring会在销毁Bean之前调用该方法。

    public class MyBean {
    @PreDestroy
    public void cleanup() {
    System.out.println("@PreDestroy: Cleanup method called");
    }
    }

示例代码

下面是一个完整的示例,展示了如何在一个Bean中实现和使用这些接口和注解。

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@Lazy
public class MyBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private String beanName;
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;

    // 构造函数
    public MyBean() {
        System.out.println("MyBean instance created.");
    }

    // BeanNameAware接口方法
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("BeanNameAware: Bean name is " + name);
    }

    // BeanFactoryAware接口方法
    @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactoryAware: BeanFactory is set");
    }

    // ApplicationContextAware接口方法
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("ApplicationContextAware: ApplicationContext is set");
    }

    // InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: afterPropertiesSet method called");
    }

    // @PostConstruct注解的方法
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct: Initialization method called");
    }

    // @PreDestroy注解的方法
    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy: Cleanup method called");
    }

    // DisposableBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: destroy method called");
    }
}

总结

Spring Bean的生命周期是一个高度灵活和可扩展的过程。通过实现不同的生命周期回调接口和使用注解,我们可以控制Bean在各个阶段的行为。这使得我们能够有效地管理Bean的初始化和清理,尤其是在处理外部资源(如数据库连接、网络连接等)时尤为重要。

此外,Spring还提供了许多其他的扩展点,如BeanPostProcessorBeanFactoryPostProcessor等,这些都可以用来在Bean的生命周期中插入自定义逻辑。

相关推荐
总是学不会.3 分钟前
【集合】Java 8 - Stream API 17种常用操作与案例详解
java·windows·spring boot·mysql·intellij-idea·java集合
潜意识起点13 分钟前
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
java·spring boot·后端
mxbb.14 分钟前
单点Redis所面临的问题及解决方法
java·数据库·redis·缓存
云和数据.ChenGuang39 分钟前
《XML》教案 第1章 学习XML基础
xml·java·学习
王·小白攻城狮·不是那么帅的哥·天文1 小时前
Java操作Xml
xml·java
发飙的蜗牛'1 小时前
23种设计模式
android·java·设计模式
music0ant1 小时前
Idean 处理一个项目引用另外一个项目jar 但jar版本低的问题
java·pycharm·jar
zxguan1 小时前
Springboot 学习 之 logback-spring.xml 日志压缩 .tmp 临时文件问题
spring boot·学习·spring
陈大爷(有低保)1 小时前
logback日志控制台打印与写入文件
java
繁川1 小时前
深入理解Spring AOP
java·后端·spring