# 三层架构与依赖注入

在写 SpringBoot 时,曽多次遇到 @Component 注入失败的问题,由于对框架的细节不甚了解,最后都是曲线救国:把需要的 @Component 的方法改为静态方法调用。

于是,一个问题油然而生:在 SpringBoot 常用的三层架构中, Controller、Service 和 Repository 本身都是不需要维护状态的,只需要提供方法,那么为什么不直接用 static 实现,而是采用依赖注入调用呢?

通过了解,@Controller、@Service 和 @Repository 三者,不同的注解名只是为了分类,其作用完全相同,就是将类标记为单例的 Bean 交给 Spring 容器管理。这样一来疑惑反而更大了,既然都是单例的,那干嘛不直接用静态函数搞定算了?

在网上查阅了大量资料后发现,大部分人认为实例化方法更好,但只是因为一直用没出什么问题,少部分人能给出一些理由,大致可以归纳为以下几类:

静态方法在应用初始化时就会生成并一直存在于内存中,相对于实例化方法,虽然被调用时省去了创建实例这一步,但本质上是用空间换时间。

乍一听很有道理,但经过分析考证,这个说法是 错误 的。

静态方法并没有多占空间。静态方法初始存在并一直存在于内存中,这没有错,但单例的 Bean 也会在 SpringBoot 应用初始化时被创建;此外,不论是否静态,方法代码总会被加载到一片不可写的内存区域,不同的实例在调用同一个方法时访问的也是同一片内存区域。

依赖注入便于替换实现,便于测试。

这一点是很有道理的,原贴 (opens new window)中还有代码示例。

在 Service 层,XXService 应该被设计为接口,在开发环境中,通过 Mock 构建用于测试的实现,而在生产环境中则换用真实实现;在 Repository 层,XXMapper 应该被设计为接口,通过 MyBatis、Hibernate等框架实现,便于换用。而如果使用静态方法,就没有办法实现这些需求。

其实这也是依赖注入的好处之一:松耦合。如果使用静态方法耦合就无法避免,不符合 OOP 的思想。

依赖注入可以享受 Spring 容器提供的强大功能。

正是因为有了创建实例对象这一步,调用方法才能够被 Spring 容器获知并管理。AOP、事务等等,这些与 Service 无关但又必需的功能,都不应该侵入业务代码,这才是依赖注入的高明之处。

# 总结

总而言之,通过依赖注入调用实例方法比使用静态方法更好,这个结论是一定的。

联系到项目的实际情况,我发现,其实是因为我的项目过于简单——没有开发生产环境分离、没有单元测试、没有事务和切面……当你的需求足够简单时,静态方法自然也能支棱起来。

我的 @Component 注入失败问题,要么是设计不合理,要么是存在一些编码上的错误,可惜没有留存备份,现在已经无处可查了~

# 参考

在java三层架构中,单例的service层为什么不使用静态static方式来实现? (opens new window)

【讨论贴】Dao层的调用是否应该做成静态 (opens new window)

经典:静态方法和实例方法的区别 (opens new window)

Last Updated: 8/25/2021, 5:13:24 PM