摸鱼学 Spring:Bean 的生命周期,面试官为啥总揪着问?

一、引言:摸鱼时的灵魂拷问

"嘿,摸鱼刷手机,突然想到面试官上次问 Spring Bean 的生命周期,当时支支吾吾没答好。现在得补补,不然下次面试又栽跟头。咱用大白话聊聊,就当摸鱼学习了。"

二、Bean 生命周期:从出生到死亡的 "剧本"

1. 实例化(new 对象)

  • 大白话 :Spring 先给 Bean "生" 出来,调用构造方法,就像new UserService(),这是第一步。

  • 代码举例

    csharp 复制代码
    public class UserService {
        public UserService() {
            System.out.println("UserService实例化(构造方法)");
        }
    }

2. 属性注入(填属性)

  • 大白话 :给刚生的 Bean "穿衣服",把依赖的其他 Bean 或配置值塞进去。比如@Autowired注入 DAO,或者 XML 里的<property>

  • 代码举例

    kotlin 复制代码
    public class UserService {
        @Autowired
        private UserDAO userDAO; // 注入属性
    }

3. 初始化前(BeanPostProcessor 预处理)

  • 大白话:Spring 的 "前置处理器" 先检查 Bean,搞点 AOP 代理啥的(比如事务增强)。这时候 Bean 还没完全初始化,先 "整整容"。

  • 代码举例(BeanPostProcessor)

    typescript 复制代码
    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            System.out.println("初始化前处理:" + beanName);
            return bean;
        }
    }

4. 初始化(自己的初始化逻辑)

  • 大白话 :Bean 自己的 "初始化仪式",比如实现InitializingBean接口(afterPropertiesSet方法),或者配置init-method。这时候 Bean 终于 "ready" 了。

  • 代码举例(InitializingBean)

    csharp 复制代码
    public class UserService implements InitializingBean {
        @Override
        public void afterPropertiesSet() {
            System.out.println("UserService初始化(afterPropertiesSet)");
        }
    }
    // 或者XML配置init-method:<bean init-method="init"/>
    public void init() {
        System.out.println("自定义初始化方法");
    }

5. 初始化后(BeanPostProcessor 后处理)

  • 大白话:"后置处理器" 再检查一遍,比如生成最终的代理对象(AOP 的最后一步)。这时候 Bean 完全 "打扮好",可以用了。

  • 代码举例(BeanPostProcessor)

    typescript 复制代码
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("初始化后处理:" + beanName);
        return bean; // 比如返回代理后的Bean
    }

6. 使用(被调用)

  • 大白话:Bean 开始 "干活",比如处理 HTTP 请求、执行业务逻辑,这是它的 "职业生涯"。

7. 销毁(容器关闭时清理)

  • 大白话 :Spring 容器关闭时,Bean "退休",执行销毁逻辑。比如实现DisposableBeandestroy方法),或配置destroy-method,释放资源(比如数据库连接)。

  • 代码举例(DisposableBean)

    csharp 复制代码
    public class UserService implements DisposableBean {
        @Override
        public void destroy() {
            System.out.println("UserService销毁(destroy)");
        }
    }
    // 或者XML配置destroy-method:<bean destroy-method="destroy"/>
    public void destroy() {
        System.out.println("自定义销毁方法");
    }

三、核心代码串起来(XML 配置示例,简单明了)

ini 复制代码
<beans>
    <bean id="userService" class="com.example.UserService" 
          init-method="init" destroy-method="destroy">
        <property name="userDAO" ref="userDAO"/>
    </bean>
    <bean class="com.example.MyBeanPostProcessor"/>
</beans>
  • 执行顺序:构造→注入→初始化前→init 方法→初始化后→使用→destroy 方法(容器关闭时)。

四、实际场景:这玩意儿有啥用?

  1. AOP 实现:BeanPostProcessor 在初始化前后生成代理(比如事务切面),这就是 Spring AOP 的底层逻辑。
  2. 资源初始化 / 销毁:比如数据库连接池在初始化时创建连接,销毁时关闭(用 init-method 和 destroy-method)。
  3. 参数校验:初始化前检查 Bean 的属性是否合法(比如 @Validated 注解的处理,类似 BeanPostProcessor 的逻辑)。
  4. 框架扩展 :比如 MyBatis 的SqlSessionFactoryBean,在初始化时解析 XML,创建 SqlSessionFactory(用 afterPropertiesSet 方法)。

五、面试官为啥总问?

  1. 考察 Spring 核心理解:Bean 生命周期是 Spring 容器的核心机制,懂了它,才知道 Spring 如何管理对象,为啥能实现依赖注入、AOP 这些功能。
  2. 排查问题能力:比如 Bean 初始化失败(比如 init-method 抛异常),懂生命周期才能快速定位(是注入错了?还是初始化逻辑有问题?)。
  3. 框架扩展能力:如果你要写自定义 Spring Starter(比如集成 Redis),需要在 Bean 生命周期的某个阶段注册组件(比如初始化后创建 Redis 连接),这时候必须懂生命周期。

六、摸鱼总结

"原来 Bean 的生命周期就是这么个流程!现在再被面试官问,能从实例化到销毁,一步步说清楚。下次写代码时,遇到 Bean 初始化的问题,也知道从哪个阶段排查。摸鱼学技术,真香!"

相关推荐
程序员cxuan2 分钟前
今天看到很多人讨论 Linux 终于要接受 AI 提交的代码了,我的第一反应是,真的吗?作为喷 AI 最狠的祖师爷到底咋看这件事儿?
后端·程序员
XDHCOM2 分钟前
Redis节点故障自动恢复机制详解,如何快速抢救故障节点,确保数据不丢失?
java·数据库·redis
何陋轩4 分钟前
GitHub Copilot深度使用指南:手把手教你在IDEA中榨干AI生产力
人工智能·后端
风吹迎面入袖凉4 分钟前
【Redis】Redisson分布式锁原理
java·服务器·开发语言
fish20264 分钟前
车载日志限流稽查系统
后端
云边有个稻草人4 分钟前
NFS 环境 KES 安装 Operation not permitted 报错排查 + 最佳实践
后端
QCzblack5 分钟前
BugKu BUUCTF ——Reverse
java·前端·数据库
Orange_sparkle8 分钟前
learn claude code学习记录-S02
java·python·学习
李白你好10 分钟前
Java GUI-未授权漏洞检测工具
java·开发语言
aq553560029 分钟前
四大编程语言对比:PHP、Python、Java、易语言
java·python·php