摸鱼学 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 初始化的问题,也知道从哪个阶段排查。摸鱼学技术,真香!"

相关推荐
天天摸鱼的java工程师4 分钟前
深入理解 Spring 核心:IOC 与 AOP 的原理与实践
java·后端
漫步者TZ5 分钟前
【Netty系列】解决TCP粘包和拆包:LengthFieldBasedFrameDecoder
java·网络协议·tcp/ip·netty
京东零售技术17 分钟前
在京东 探索技术的无限可能
面试
编程轨迹18 分钟前
使用 Playwright Java 框架创建自定义的请求和响应日志记录器
后端
愿你是阳光060731 分钟前
Java-redis实现限时在线秒杀功能
java·redis·bootstrap
Moonbit36 分钟前
征文开启|写一篇能跑的文档,赢 MoonBit 周边 & 成为官方示例
后端
我爱Jack39 分钟前
Spring Boot统一功能处理深度解析
java·spring boot·后端
苦学编程的谢1 小时前
Java网络编程API 1
java·开发语言·网络
惜鸟1 小时前
# LLM统一网关:LiteLLM 详细介绍(实践篇)
后端·openai
寒山李白1 小时前
Java 依赖注入、控制反转与面向切面:面试深度解析
java·开发语言·面试·依赖注入·控制反转·面向切面