Spring这6种初始化Bean的方式,个个是精华!

举报
一颗小谷粒 发表于 2025/06/30 21:59:54 2025/06/30
【摘要】 Spring这6种初始化Bean的方式,个个是精华!作为一个 Java开发工程师,Spring应该是接触最多的一个框架,而 Bean又是 Spring的基石。那么,在 Spring中,有多少种 Bean初始化的方式,这些方式有什么优缺点?我们该如何选择?这篇文章,我们来聊一聊。总体来说,Spring初始化Bean 包含以下6种方法:1. XML配置方式在 Spring发展初期,XML配置方式...

Spring这6种初始化Bean的方式,个个是精华!

作为一个 Java开发工程师,Spring应该是接触最多的一个框架,而 Bean又是 Spring的基石。那么,在 Spring中,有多少种 Bean初始化的方式,这些方式有什么优缺点?我们该如何选择?这篇文章,我们来聊一聊。

总体来说,Spring初始化Bean 包含以下6种方法:

1. XML配置方式

在 Spring发展初期,XML配置方式是最传统也是最流行的初始化方式,尽管如今大家更多选择注解方式,但了解这个"祖传手艺"还是很有必要的。

如下示例,展示了如何使用XML配置初始化和销毁方法:

<bean id="testService" class="com.yuanjava.TestService" init-method="init" destroy-method="cleanup"/>

对应的Java类:

public class TestService {
    public void init() {
        System.out.println("XML配置的init方法被调用啦!");
    }
    
    public void cleanup() {
        System.out.println("XML配置的destroy方法被调用啦!");
    }
}

优点:

  1. 集中式管理:一个XML文件就可以管理多个Bean的初始化和销毁逻辑。
  2. 修改无需重新编译:直接改了XML配置重启就行,不用重新打包部署
  3. 解耦性极强:配置和实现完全分离的方式,特别适合需要频繁切换实现的场景
  4. 历史兼容性好:早期的Spring版本也支持XML配置,不影响现有的项目

缺点:

  1. 配置冗长:XML配置文件比较冗长,维护成本大
  2. 类型不安全:编译期不报错,如果XML配置有错误,需要运行时会报错
  3. 重构困难: 当你重命名一个类时,IDE不会自动更新XML中的class属性

思考题:有没有小伙伴还记得,为什么我们那时候要在 XML里配init-method,而不是直接在类里写个构造方法呢?(答案后面揭晓)

2. 注解方式

随着 Spring 生态的发展,特别是 Spring Boot的普及,注解方式已经才能开发者的标配,下面是一个简单的示例:

@Component
public class TestService {
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("@PostConstruct方法执行了");
    }
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy方法执行了");
    }
}

优点:

  1. 代码即配置:只需要写注解,就能完成初始化和销毁逻辑
  2. 强大的IDE支持:IDE可以直接帮你生成这两个方法,无需手动写
  3. 类型安全:编译期检查,IDE会报错,防止出错

缺点:

  1. 分散式配置:一个类只能管理一个Bean的初始化和销毁逻辑,不够集中
  2. 修改需要重新编译:直接改了Java代码,需要重新打包部署
  3. 运行时开销:启动时Spring需要扫描所有注解,会造成一定的性能损耗

3. InitializingBean接口

如果你想玩深度,那么InitializingBean接口绝对是首选,它是 Spring的亲儿子,这个接口中定义了一个方法:

@Component
public class TestService implements InitializingBean {
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean的afterPropertiesSet方法被调用");
    }
}

优点:

  1. 绝对执行顺序保证:只要实现了InitializingBean接口,就能保证初始化的顺序
  2. 框架原生支持:Spring框架本身就支持InitializingBean,Spring的亲儿子待遇
  3. 明确契约:实现接口是一种显式的契约声明

缺点:

  1. 单一方法限制:只能实现一个初始化方法,不够灵活
  2. 异常处理尴尬:只能抛出异常,无法返回值,不够灵活

虽然这种方式很直接,但因为它把代码和 Spring框架耦合在一起了,所以现在不太推荐使用。不过了解它有助于我们理解 Spring的原理。

4. @Bean的 initMethod属性

@Bean的 initMethod属性采用了配置类的玩法,示例代码如下:

@Configuration
publicclass AppConfig {
    @Bean(initMethod = "init", destroyMethod = "cleanup")
    public FancyService fancyService() {
        returnnew FancyService();
    }
}

publicclass FancyService {
    public void init() {
        System.out.println("@Bean的initMethod指定的方法");
    }
    
    public void cleanup() {
        System.out.println("@Bean的destroyMethod指定的方法");
    }
}

优点:

  1. 无侵入性:不需要改动原来的类,只需要改动配置文件,就能完成初始化和销毁逻辑
  2. 统一生命周期管理:所有Bean的生命周期方法名在配置处一目了然,特别适合需要严格规范的中大型项目

缺点:

  1. 方法名硬编码:全部通过 initMethod = "xxx"命名,存在重构风险
  2. 调试困难:initMethod的调用被Spring代理层层包裹

大家有没有注意到,这里的 destroyMethod有个隐藏特性?如果我把cleanup方法改个名,但不改destroyMethod配置,会发生什么?

5. BeanPostProcessor

这个可就厉害了,它能插手所有 Bean的初始化过程:

@Component
publicclass TestProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("Before初始化: " + beanName);
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("After初始化: " + beanName);
        return bean;
    }
}

优点:

  1. 全局控制:可以使用该技术在不修改业务代码的情况下,为整个系统添加了方法调用日志
  2. AOP基础:Spring AOP就是通过BeanPostProcessor实现的(具体是AbstractAutoProxyCreator)

缺点:

  1. 性能损耗:要求所有 BeanPostProcessor必须加@Order和严格的异常处理
  2. 调试困难:复杂的调用栈

6. @EventListener

Spring的@EventListener事件机制也可以用来做初始化:

@Component
public class EventInitService {
    
    @EventListener(ContextRefreshedEvent.class)
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("容器刷新完毕,开始执行初始化逻辑");
    }
}

优点:

  1. 松耦合设计:事件发布者和监听者完全解耦
  2. 灵活监听:支持多事件类型、条件过滤
  3. 异步支持:简单注解即可实现异步处理
  4. 顺序控制:通过@Order指定监听顺序

缺点:

  1. 调试困难:事件链路追踪复杂
  2. 类型安全:运行时才能发现事件类型不匹配
  3. 性能风险:同步事件会阻塞发布者线程
  4. 事务边界:事件处理与事务的交互需要特别注意

7. Bean初始化顺序

上面,我们已经分析了 6种初始化方式,那么,这几种方式的顺序是什么?来,看一个综合例子:

@Component
publicclass OrderDemoBean implements InitializingBean {
    
    public OrderDemoBean() {
        System.out.println("1. 构造方法");
    }
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("3. @PostConstruct");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("4. InitializingBean");
    }
    
    public void initMethod() {
        System.out.println("5. init-method");
    }
}

// 配合BeanPostProcessor的输出,完整顺序是:
// 1. 构造方法
// 2. BeanPostProcessor的postProcessBeforeInitialization
// 3. @PostConstruct
// 4. InitializingBean
// 5. init-method
// 6. BeanPostProcessor的postProcessAfterInitialization

记忆口诀:构造-BeforePost-@PostConstruct-AfterProperties-initMethod-AfterPost

8. 总结

本文,我们一起分析了Spring中 6种 Bean初始化的方式以及他们的优缺点(未做很深的原理解析,在实际开发中,因为面对的业务需求不同,可能每种方式都会使用到,所以,作为开发者,建议 6种方式都要掌握。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。