Bean 生命周期完全图解:前端同学也能看懂的 Spring 核心机制

IoC 容器与 Bean

IoC 容器

如果你做过前端,你一定见过这个模式:

js 复制代码
// Vue 3:全局注册一个依赖,后代组件随意取用
const app = createApp();
app.provide('userService', new UserService());  // 注册到"全局仓库"

// 任何后代组件
const userService = inject('userService');       // 从"全局仓库"取出来

Spring 的 IoC 容器本质上就是"全局仓库"的工业级实现:

概念 Spring Vue 类比 React 类比
容器的角色 ApplicationContext app.provide() 注册表 Context Provider 树
存放的东西 Bean(Java 对象) 注入值 / 服务实例 Context value
注册方式 @Component / @Service 等注解 app.provide(key, value) <Provider value={...}>
取用方式 @Autowired 注入(可标注在字段、Setter、构造器上) inject(key) useContext(SomeContext)

⚠️ 关键区别 :Vue/React 的依赖注入是手动注册 (你显式调用 provide 或写 <Provider>),而 Spring 是自动扫描 ------只要类上标了 @Component,容器启动时自动发现、自动创建、自动管理。

Bean 到底是什么?

Bean 是由 Spring IoC 容器负责创建、组装和管理的 Java 对象

被 Spring 管理这件事带来的好处:

  • 单例:默认只创建一个实例,全局复用(无需自己写单例模式)
  • 依赖注入:自动把需要的其他 Bean 注入进来(无需 new)
  • 生命周期回调:可以在"创建时"和"销毁时"执行自定义逻辑
  • AOP 增强:Spring 可以在你的方法前后偷偷加功能(事务、日志、缓存......)

生命周期全景图

Spring Bean 就像 React/Vue 组件,有自己的"挂载 → 更新 → 卸载"生命周期,只是叫法和细节不同

less 复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│                     Spring Bean 生命周期(完整 8 步)                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. 构造方法 (new 对象,读配置、校验参数)                                  │
│        │                                                                 │
│        ▼                                                                 │
│  2. 依赖注入 (@Autowired,把需要的其他 Bean 传进来)            │
│        │                                                                 │
│        ▼                                                                 │
│  3. Aware 接口 (BeanNameAware, ApplicationContextAware... 知道"我是谁")     │
│        │                                                                 │
│        ▼                                                                 │
│  4. BeanPostProcessor 前置处理 (postProcessBeforeInitialization)         │
│        │  类比:axios 请求拦截器 ------ 在"初始化"之前拦截                       │
│        ▼                                                                 │
│  5. @PostConstruct 初始化 (缓存预热、连接池初始化、资源准备)                │
│        │                                                                 │
│        ▼                                                                 │
│  6. BeanPostProcessor 后置处理 (postProcessAfterInitialization)          │
│        │  ⭐ AOP 代理在此处生成!(@Transactional、@Async 等的魔法时刻)     │
│        │  类比:axios 响应拦截器 ------ 在"初始化"之后拦截                     │
│        ▼                                                                 │
│  7. Bean 就绪 ------ 可供业务使用                                             │
│        │                                                                 │
│        ▼                                                                 │
│  8. @PreDestroy 销毁 (优雅停机、释放资源)                                  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

构造/注入 → @PostConstruct 初始化 → @PreDestroy 销毁,覆盖日常开发 90% 的场景。

八阶段详解

1.构造方法

前端类比:Spring 构造方法 ≈ React 函数组件执行 / Vue setup() 执行

构造方法示例:

java 复制代码
@Component
public class UserService {
    public UserService() {
        System.out.println("1. 构造器:new 对象");
    }
}

示例场景:构造阶段读取配置并校验

java 复制代码
/**
 * 支付网关客户端 ------ 构造阶段读取配置并校验
 */
@Component
public class PaymentGatewayClient {

    private final String baseUrl;
    private final int connectTimeout;

    // Spring 通过构造器将 application.yml 中的配置值注入
    public PaymentGatewayClient(
            @Value("${payment.gateway.url}") String baseUrl,
            @Value("${payment.gateway.timeout:5000}") int connectTimeout) {

        // ⚠️ 实战要点:参数校验放在构造器,fail-fast
        if (baseUrl == null || baseUrl.isBlank()) {
            throw new IllegalArgumentException(
                "payment.gateway.url 未配置,请检查 application.yml");
        }

        this.baseUrl = baseUrl;
        this.connectTimeout = connectTimeout;
    }

    // 后续业务方法...
}

2.依赖注入

前端类比:Spring 字段注入 @Autowired ≈ Vue inject() ≈ React useContext(),从"全局注册表"中按标识符查找依赖

依赖注入示例:字段注入

java 复制代码
@Component
public class UserService {
    @Autowired
    private UserMapper userMapper;
}

示例场景:业务层之间的相互调用 ------ OrderService 依赖 UserService

java 复制代码
/**
 * 订单服务 ------ 展示依赖注入的三种方式(本质都是 @Autowired)
 */
@Service
public class OrderService {
    private final UserService userService;
    private final InventoryService inventoryService;

    @Autowired  // Spring 4.3+ 如果类只有一个构造器,这个注解可以省略
    public OrderService(UserService userService, InventoryService inventoryService) {
        this.userService = userService;
        this.inventoryService = inventoryService;
    }
}

3.Aware 接口

前端类比:Aware 接口 ≈ Vue 3 的 getCurrentInstance,都是让"内部成员"有能力反查"外部环境"的元信息

常用 Aware 接口一览

接口 获取什么 什么场景用 常用度
BeanNameAware Bean 在容器中的名字 日志输出、错误追踪 ⭐⭐⭐
EnvironmentAware 环境配置(profiles、properties) dev/prod 走不同初始化逻辑 ⭐⭐⭐
ApplicationContextAware 整个 Spring 容器引用 极少数需要手动获取 Bean 的场景(推荐优先用 @Autowired 替代)
ResourceLoaderAware 资源加载器 加载 classpath 下的文件
BeanFactoryAware Bean 工厂(容器底层 API) 非常底层,99% 的业务代码不需要

示例场景一:日志里带上 Bean 名

java 复制代码
/**
 * 短信发送处理器 ------ 实现 BeanNameAware 让日志带上自己的 Bean 名
 * 场景:项目中同时存在 aliSmsHandler、tencentSmsHandler 等同类型 Bean,
 *       出问题时需要一眼看出是哪个渠道在处理
 */
@Component
public class AliSmsHandler implements BeanNameAware {

    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;  // Spring 自动传入,比如 "aliSmsHandler"
    }

    public void send(String phone, String content) {
        System.out.printf("[%s] 发送短信到 %s,内容: %s%n", beanName, phone, content);
        // 调用阿里短信 API...
    }
}

示例场景二:根据环境初始化不同的上传目录

java 复制代码
/**
 * 文件存储服务 ------ 实现 EnvironmentAware 根据 dev/prod 环境选择不同存储路径
 */
@Component
public class FileStorageService implements EnvironmentAware {

    private String uploadDir;

    @Override
    public void setEnvironment(Environment env) {
        // 根据当前激活的 profile 做不同初始化
        String[] profiles = env.getActiveProfiles();
        List<String> activeProfiles = Arrays.asList(profiles);

        if (activeProfiles.contains("dev")) {
            this.uploadDir = "/tmp/uploads";      // 开发环境:本地临时目录
        } else if (activeProfiles.contains("prod")) {
            this.uploadDir = "/data/uploads";     // 生产环境:持久化存储
        } else {
            this.uploadDir = "/var/uploads";      // 默认
        }
    }
}

4.BeanPostProcessor 前置处理

前端类比:BeanPostProcessor 前置处理 ≈ axios 请求拦截器

在容器启动时触发。每个单例 Bean 仅执行一次(初始化阶段)

java 复制代码
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("前置处理: " + beanName);
        return bean;  // 可以返回代理对象替换原 bean
    }
}

5.@PostConstruct 初始化

前端类比:@PostConstruct ≈ React useEffect(() => {}, \[\]) ≈ Vue onMounted()

适用场景:缓存预热,启动时把热点数据从 DB 加载到本地缓存,避免首次请求冷启动

java 复制代码
/**
 * 首页商品缓存 ------ 启动时从数据库预热热点数据
 */
@Service
public class HotProductCache {

    private final ProductMapper productMapper;
    private final Map<Long, Product> cache = new ConcurrentHashMap<>();
    private volatile boolean ready = false;

    public HotProductCache(ProductMapper productMapper) {
        this.productMapper = productMapper;
    }

    @PostConstruct
    public void warmUp() {
        List<Product> hotProducts = productMapper.selectHotProducts(100);
        hotProducts.forEach(p -> cache.put(p.getId(), p));
        this.ready = true;
        System.out.println("首页热门商品缓存就绪,共 " + cache.size() + " 条");
    }

    // 业务方法:对外提供数据
    public List<Product> getHotProducts() {
        return ready ? new ArrayList<>(cache.values()) : Collections.emptyList();
    }
}

6.BeanPostProcessor 后置处理

前端类比:BeanPostProcessor 前置处理 ≈ axios 响应拦截器

后置处理是AOP的关键,@Transactional、@Async、@Cacheable 这些注解之所以能生效,就是因为 Spring 在后置处理这一步,偷偷把原始 Bean 换成了一个增强后的代理对象。类似于JavaScript 的Proxy

scss 复制代码
Bean 初始化完成后                    后置处理中...
─────────────────────              ─────────────────────
  OrderService                       Spring 发现 OrderService 上有 @Transactional
  ├── placeOrder()                   ↓
  ├── cancelOrder()                 包装成代理对象返回:
  └── queryOrders()                 ┌─────────────────────────────────┐
                                    │ OrderServiceProxy              │
                                    │ ├── placeOrder() {             │
                                    │ │    开启事务                   │
                                    │ │    调用原始 placeOrder()      │
                                    │ │    提交/回滚事务              │
                                    │ │   }                          │
                                    │ ├── cancelOrder() { ... }      │
                                    │ └── queryOrders()  { ... }     │
                                    └─────────────────────────────────┘

代码示例

java 复制代码
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("6. 后置处理: " + beanName);
        // ⭐ Spring AOP 在这里生成代理对象!
        return bean;
    }
}

7. Bean 就绪

Bean 走完前 6 步后进入"就绪"状态,随时可以处理业务请求。

8. 销毁

前端类比:@PreDestroy ≈ React useEffect cleanup ≈ Vue onUnmounted()

适用场景:业务代码中的绝大多数资源释放(如关闭线程池、缓存清理、关闭数据库连接)

java 复制代码
@Component
public class UserService {
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("释放资源...");
    }
}
相关推荐
dadaobusi12 小时前
学习:RV lkvm SBI
java·学习·spring
HEJOO914 小时前
深入理解 Java volatile 关键字:原理、用法与常见误区
java·开发语言·spring
曹牧14 小时前
Java:no content to map due to end of input
java·开发语言
子非鱼a14 小时前
【WEB】multiSQL
前端
阿维的博客日记14 小时前
Example 类全场景实战指南
java·mybatis
两点王爷14 小时前
SpringBoot 项目集成 GeoServer 源码,实现地图服务发布
java·spring boot·后端
Javatutouhouduan15 小时前
Java如何速通性能优化难题?
java·java面试·jvm调优·后端开发·java程序员·java八股文·java性能优化
lemon_sjdk15 小时前
DOM 节点
java·前端·javascript
nvd1115 小时前
深入现代 Web 鉴权架构:网关统一代理 (Forward-Auth) vs 前端持有 JWT 的终极选型与边缘同域实践
前端·架构·状态模式
leoZ23115 小时前
2026-09-09-springboot-cloud-deploy-pitfalls
java·前端·javascript·vue.js·人工智能·spring boot·后端