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的生命周期中插入自定义逻辑。

相关推荐
Theodore_10223 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
冰帝海岸4 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象4 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了5 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
小二·5 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王5 小时前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康5 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神6 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
qq_327342736 小时前
Java实现离线身份证号码OCR识别
java·开发语言