Spring Bean 生命周期自定义扩展示例

Spring Bean 生命周期自定义扩展实战示例

本文档聚焦于 Spring Bean 生命周期中最常用、最实用的自定义扩展场景,通过可直接运行的代码示例,展示不同扩展点的使用方式和典型业务场景。

前提说明

所有示例基于 Spring Boot 3.x 实现,核心依赖仅需引入 Spring Boot 基础依赖:

xml

复制代码
<!-- pom.xml 核心依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

扩展场景 1:初始化阶段加载配置 / 创建资源

场景描述

Bean 初始化时加载外部配置文件、创建数据库连接池、初始化缓存等(最常用的扩展场景)。

实现方式(推荐自定义方法,解耦)

复制代码
import org.springframework.stereotype.Component;
import java.io.FileInputStream;
import java.util.Properties;

/**
 * 示例:初始化时加载配置文件,销毁时关闭资源
 */
@Component
public class ResourceManagerBean {
    // 模拟配置属性
    private Properties configProps;
    // 模拟资源(如连接池、文件流)
    private FileInputStream configFileStream;

    // 自定义初始化方法(通过 @Bean(initMethod) 或 @PostConstruct 注解)
    // 推荐使用 @PostConstruct(无需在 @Bean 中配置,更简洁)
    @javax.annotation.PostConstruct
    public void initResource() {
        System.out.println("【初始化扩展】加载配置文件并创建资源");
        try {
            // 1. 加载配置文件
            configFileStream = new FileInputStream("application-custom.properties");
            configProps = new Properties();
            configProps.load(configFileStream);
            System.out.println("加载配置:app.name = " + configProps.getProperty("app.name"));

            // 2. 模拟创建数据库连接池/缓存等资源
            // ... 业务逻辑 ...
        } catch (Exception e) {
            throw new RuntimeException("初始化资源失败", e);
        }
    }

    // 自定义销毁方法(推荐 @PreDestroy)
    @javax.annotation.PreDestroy
    public void destroyResource() {
        System.out.println("【销毁扩展】关闭资源释放连接");
        try {
            // 关闭文件流/连接池等资源
            if (configFileStream != null) {
                configFileStream.close();
            }
            // 清理缓存/关闭连接池
            // ... 业务逻辑 ...
        } catch (Exception e) {
            throw new RuntimeException("销毁资源失败", e);
        }
    }

    // 业务方法
    public String getConfig(String key) {
        return configProps.getProperty(key);
    }
}

测试验证

复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class BeanExtensionApplication {
    public static void main(String[] args) {
        // 启动容器(触发初始化)
        ConfigurableApplicationContext context = SpringApplication.run(BeanExtensionApplication.class, args);
        
        // 使用 Bean
        ResourceManagerBean resourceBean = context.getBean(ResourceManagerBean.class);
        System.out.println("业务使用:" + resourceBean.getConfig("app.name"));
        
        // 关闭容器(触发销毁)
        context.close();
    }
}

输出结果

复制代码
【初始化扩展】加载配置文件并创建资源
加载配置:app.name = SpringBeanExtensionDemo
业务使用:SpringBeanExtensionDemo
【销毁扩展】关闭资源释放连接

扩展场景 2:BeanPostProcessor 全局增强(统一处理所有 Bean)

场景描述

对容器中所有 / 指定 Bean 进行统一增强,如:

  • 给所有 Bean 添加日志埋点
  • 统一设置 Bean 属性
  • 替换 Bean 实例(如动态代理)

实现示例(统一设置 Bean 属性 + 日志埋点)

复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 示例:BeanPostProcessor 全局增强
 * 1. 给所有以 "demo" 开头的 Bean 添加统一标识
 * 2. 记录所有 Bean 的初始化前后日志
 */
@Component
public class GlobalBeanEnhancer implements BeanPostProcessor {

    // 初始化前置处理(所有 Bean 初始化前执行)
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("\n【BeanPostProcessor 前置】处理 Bean:" + beanName + ",类型:" + bean.getClass().getSimpleName());
        
        // 对指定 Bean 增强:设置统一属性
        if (beanName.startsWith("demo") && bean instanceof DemoBusinessBean) {
            DemoBusinessBean demoBean = (DemoBusinessBean) bean;
            demoBean.setSystemTag("GLOBAL_2026"); // 统一设置系统标识
            System.out.println("为 " + beanName + " 设置系统标识:GLOBAL_2026");
        }
        return bean; // 返回原 Bean(可替换为代理对象)
    }

    // 初始化后置处理(所有 Bean 初始化后执行)
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【BeanPostProcessor 后置】处理 Bean:" + beanName + ",初始化完成");
        return bean;
    }
}

// 测试用业务 Bean
@Component("demoOrderBean")
class DemoBusinessBean {
    private String systemTag;
    private String orderId;

    @PostConstruct
    public void init() {
        System.out.println("DemoBusinessBean 初始化,系统标识:" + systemTag);
    }

    // getter/setter
    public void setSystemTag(String systemTag) {
        this.systemTag = systemTag;
    }
}

输出结果

复制代码
【BeanPostProcessor 前置】处理 Bean:demoOrderBean,类型:DemoBusinessBean
为 demoOrderBean 设置系统标识:GLOBAL_2026
DemoBusinessBean 初始化,系统标识:GLOBAL_2026
【BeanPostProcessor 后置】处理 Bean:demoOrderBean,初始化完成

扩展场景 3:Aware 接口感知容器信息

场景描述

Bean 需要获取容器内的核心信息(如 Bean 名称、ApplicationContext 实例),实现与 Spring 容器的交互。

实现示例(获取容器上下文 + Bean 名称)

复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 示例:Aware 接口获取容器信息
 * 1. 获取当前 Bean 的名称
 * 2. 获取 ApplicationContext 实例,操作容器
 */
@Component
public class ContainerAwareBean implements BeanNameAware, ApplicationContextAware {
    // 当前 Bean 名称
    private String currentBeanName;
    // Spring 容器上下文
    private ApplicationContext applicationContext;

    // 实现 BeanNameAware,获取 Bean 名称
    @Override
    public void setBeanName(String beanName) {
        this.currentBeanName = beanName;
        System.out.println("【Aware 扩展】获取当前 Bean 名称:" + beanName);
    }

    // 实现 ApplicationContextAware,获取容器上下文
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("【Aware 扩展】获取 ApplicationContext 实例");
        
        // 示例:通过容器获取其他 Bean
        DemoBusinessBean demoBean = applicationContext.getBean(DemoBusinessBean.class);
        System.out.println("通过容器获取 DemoBusinessBean:" + demoBean);
    }

    // 业务方法:使用容器信息
    public void doBusiness() {
        System.out.println("当前 Bean 名称:" + currentBeanName);
        // 获取容器中所有 Bean 名称
        String[] allBeanNames = applicationContext.getBeanDefinitionNames();
        System.out.println("容器中 Bean 总数:" + allBeanNames.length);
    }
}

测试调用

复制代码
// 在主类中添加
ContainerAwareBean awareBean = context.getBean(ContainerAwareBean.class);
awareBean.doBusiness();

输出结果

复制代码
【Aware 扩展】获取当前 Bean 名称:containerAwareBean
【Aware 扩展】获取 ApplicationContext 实例
通过容器获取 DemoBusinessBean:com.example.DemoBusinessBean@xxxx
当前 Bean 名称:containerAwareBean
容器中 Bean 总数:xxx(根据实际加载的 Bean 数量)

扩展场景 4:原型 Bean 的自定义销毁(手动管理)

场景描述

原型(Prototype)Bean 的销毁方法不会被 Spring 容器自动调用,需手动触发销毁逻辑。

实现示例

复制代码
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * 示例:原型 Bean 的自定义销毁
 */
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 原型作用域
public class PrototypeBean {
    // 模拟资源
    private String resourceId;

    public PrototypeBean() {
        this.resourceId = "proto_" + System.currentTimeMillis();
        System.out.println("创建原型 Bean:" + resourceId);
    }

    // 自定义销毁方法(容器不会自动调用)
    public void manualDestroy() {
        System.out.println("手动销毁原型 Bean:" + resourceId);
        // 清理资源逻辑
    }
}

调用示例(手动销毁)

复制代码
// 在主类中
// 获取原型 Bean(每次获取都是新实例)
PrototypeBean proto1 = context.getBean(PrototypeBean.class);
PrototypeBean proto2 = context.getBean(PrototypeBean.class);

// 业务使用后手动销毁
proto1.manualDestroy();
proto2.manualDestroy();

输出结果

复制代码
创建原型 Bean:proto_1710000000000
创建原型 Bean:proto_1710000000001
手动销毁原型 Bean:proto_1710000000000
手动销毁原型 Bean:proto_1710000000001

总结

  1. 初始化 / 销毁扩展 :优先使用 @PostConstruct@PreDestroy 注解(解耦,无需实现接口),适合加载 / 释放资源、初始化配置等场景;
  2. 全局 Bean 增强 :使用 BeanPostProcessor 实现所有 / 指定 Bean 的统一修改、日志埋点、代理增强;
  3. 容器信息感知 :通过 Aware 接口获取 Bean 名称、ApplicationContext 等容器信息,实现与 Spring 容器的交互;
  4. 原型 Bean 销毁:Spring 不自动管理,需手动调用自定义销毁方法清理资源。

这些扩展点覆盖了日常开发中 90% 以上的 Bean 生命周期自定义需求,优先选择注解式(@PostConstruct/@PreDestroy)而非接口式(InitializingBean/DisposableBean),可降低与 Spring 框架的耦合度。

相关推荐
sanyii3131312 小时前
k8s工作负载-ReplicaSet控制器
java·git·kubernetes
会员源码网2 小时前
泛型通配符误用导致的类型转换致命异常
java
弹简特2 小时前
【JavaEE17-后端部分】 MyBatis 入门第一篇:准备工作与第一个查询
spring boot·spring·mybatis
冬夜戏雪2 小时前
【学习日记】
java·开发语言·数据库
无心水2 小时前
【OpenClaw:认知启蒙】4、OpenClaw灵魂三件套:SOUL.md/AGENTS.md/MEMORY.md深度解析
java·人工智能·系统架构
Java水解2 小时前
Spring Boot 数据缓存与性能优化
spring boot·后端
她说..2 小时前
Redis 中常用的操作方法
java·数据库·spring boot·redis·缓存
white-persist2 小时前
【红队渗透】Cobalt Strike(CS)红队详细用法实战手册
java·网络·数据结构·python·算法·安全·web安全
Arya_aa2 小时前
编程题:实现汽车租赁公司汽车出租方案
java