为什么使用 Spring 管理 Bean,而不是手动 new

在刚开始学习 Java 开发时,我们通常会这样创建对象:

UserService userService = new UserService();
OrderService orderService = new OrderService(userService);

这样的方式简单直观,但在实际开发中,尤其是复杂的企业级项目中,这种“手动 new”的方式很快会暴露出种种问题。
Spring 框架的 IoC(控制反转)容器 正是为了解决这些问题而诞生的。

本文将通过代码示例和场景分析,讲述为什么我们要让 Spring 来管理 Bean,而不是自己 new。

一、从一个简单例子说起

假设我们有一个电商系统中的订单模块:

public class OrderService {
    private final UserService userService = new UserService();
    private final PaymentService paymentService = new PaymentService();

    public void createOrder() {
        userService.validateUser();
        paymentService.pay();
    }
}

这段代码看似没问题,但已经埋下了“灾难”的种子。

二、手动 new 的五大问题

1. 强耦合 —— 改动一个类,牵一发动全身

OrderService 直接在内部 new 了 UserService 和 PaymentService,这意味着它强依赖于具体实现类

一旦我们希望使用新的支付方式:

public class PaymentServiceV2 extends PaymentService { ... }

想切换到新版本,就得改源码:

private final PaymentService paymentService = new PaymentServiceV2(); // 改这里

这违反了 开闭原则(OCP):软件应该对扩展开放,对修改关闭。

2. 无法单元测试 —— Mock 失效

如果要对 OrderService 做单元测试,你可能希望模拟依赖:

PaymentService mockPaymentService = Mockito.mock(PaymentService.class);
OrderService orderService = new OrderService(userService, mockPaymentService);

但如果 OrderService 内部自己 new:

private final PaymentService paymentService = new PaymentService();

那你根本无法替换掉这个实例。
结果是:测试会真的调起支付接口 ❌
Mock 彻底失效,测试不可控。

3. AOP 失效 —— 无法被 Spring 增强

假设 PaymentService 上有事务注解:

@Service
@Transactional
public class PaymentService { ... }

当你在 OrderService 中自己 new 时:

private final PaymentService paymentService = new PaymentService();

此时这个对象不是由 Spring 创建的,也就不会被 Spring AOP 代理。
事务、日志、限流、缓存等增强功能都会失效。

而如果是通过 Spring 注入:

@Autowired
private PaymentService paymentService;

Spring 会生成代理对象,AOP 才能生效 ✅。

4. 生命周期不可控

Spring 容器会统一管理 Bean 的生命周期:

  • 创建时机(单例/多例)
  • 销毁顺序
  • 初始化钩子(@PostConstruct)

但如果你自己 new:

  • Spring 不知道它的存在;
  • 也不会帮你清理、监控或追踪它;
  • 依赖的资源可能泄露。
5. 难以扩展、维护成本高

有同学说可以通过构造函数传入依赖类的方式解决问题1和2,但这已经是依赖式注入(DI)的思想了,只是没有进行控制反转(IoC)。(下面会介绍依赖式注入和控制反转)
但随着项目复杂度上升,类与类之间的依赖会越来越多。
如果所有依赖都手动 new,构造函数会变得臃肿:

OrderService orderService = new OrderService(
    new UserService(
        new UserDao(new DataSource(...))
    ),
    new PaymentService(
        new PaymentDao(new DataSource(...))
    )
);

而如果交给 Spring,只需:

@Autowired
private UserService userService;
@Autowired
private PaymentService paymentService;

Spring 自动解析依赖关系,代码清爽、可维护。

三、Spring 是如何解决这些问题的?

Spring 的核心思想之一是 IoC(Inversion of Control,控制反转)
所谓控制反转,就是把对象创建与依赖关系的管理交由容器完成,而不是在内部显式 new 出来。把“谁来控制对象的创建”从程序员反转给框架
依赖注入(Dependency Injection, DI) 是实现 IoC 的主要方式 —— 容器在创建对象时,会自动将其所需依赖“注入”进去,让组件之间解耦。具体实现方式是“对象不自己创建依赖,而由外部注入”,例如@Autowired、构造函数注入等。

也就是说:

  • 以前我们手动 new;
  • 现在由 Spring 容器统一创建、管理和注入依赖。

四、总结

维度 手动 new Spring IoC 管理
对象创建 程序员手动 容器自动
依赖注入 硬编码 自动装配
可测试性
可扩展性
生命周期 程序员控制 容器管理
AOP 支持
耦合度
🧩 一句话总结

Spring 管理 Bean 的本质,不是为了“少写几行代码”,
而是为了让系统具备解耦、扩展、测试、演化的能力。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容