
本文介绍在 Spring 应用中,当多个子类继承同一抽象父类且共用相同依赖(如 Tesla 服务)时,如何通过构造函数注入 + 单例 Bean 机制,让所有子类实例共享父类中持有的同一对象引用,从而避免重复创建 List 等高内存开销对象。
本文介绍在 spring 应用中,当多个子类继承同一抽象父类且共用相同依赖(如 `tesla` 服务)时,如何通过构造函数注入 + 单例 bean 机制,让所有子类实例共享父类中持有的同一对象引用,从而避免重复创建 `list
在 Spring 应用开发中,常遇到多子类复用同一业务逻辑与共享依赖的场景。例如,OhioServiceCenter 和 FloridaServiceCenter 均继承自抽象基类 TeslaServiceCenter,二者均需调用 Tesla.getCars() 获取车辆库存列表。但若每个子类都独立注入 Tesla 并各自调用 getCars(),即使返回内容相同,也会因每次新建 List
关键在于:共享对象本身(Tesla),而非其返回值。Spring 默认将 @Component 或 @Service 标注的 Bean 设为单例(@Scope("singleton")),这意味着整个应用上下文中仅存在一个 Tesla 实例。只要确保该 Bean 正确声明并被统一注入,所有子类获取的便是同一对象引用。
一款AI演示文稿工具,主要用于DeepSeek AI加持,输入主题生成专业PPT,支持Word/PDF等45种文档导入,职场汇报、教学提案轻松搞定,适合需要提升相关任务效率的用户。
✅ 正确实践:采用构造函数注入 + 抽象父类持有依赖
摒弃字段注入和延迟初始化,改用显式构造器传递依赖,既符合 Spring 最佳实践,也天然支持不可变性与测试友好性:
// 抽象父类:持有 Tesla 引用,不自行创建或缓存 List<car>
public abstract class TeslaServiceCenter {
protected final Tesla tesla; // final 保证线程安全与不可变性
protected TeslaServiceCenter(Tesla tesla) {
this.tesla = tesla;
}
// 子类可直接复用此方法,返回的是同一 Tesla 实例的 getCars() 结果
protected List<car> getInventory() {
return tesla.getCars(); // 注意:每次调用仍新建 List,但 Tesla 实例唯一
}
public abstract void doService();
}</car></car>
@Component
public class OhioServiceCenter extends TeslaServiceCenter {
public OhioServiceCenter(Tesla tesla) {
super(tesla); // 注入同一个 Tesla 单例
}
@Override
public void doService() {
List<car> inventory = getInventory(); // 共享 Tesla 实例,但 List 仍每次新建
// ... Ohio 特定业务逻辑
}
}
@Component
public class FloridaServiceCenter extends TeslaServiceCenter {
public FloridaServiceCenter(Tesla tesla) {
super(tesla); // 同一 Tesla 实例注入
}
@Override
public void doService() {
List<car> inventory = getInventory(); // 复用相同 Tesla,避免 Tesla 对象重复创建
// ... Florida 特定业务逻辑
}
}</car></car>
⚠️ 重要说明与优化建议:
- Tesla 必须是 Spring 管理的单例 Bean(默认即满足),否则无法保证子类注入的是同一实例;
- 若 getCars() 返回的 List
是核心性能瓶颈,应在 Tesla 内部做缓存(如 @Cacheable、ConcurrentHashMap 或懒加载静态缓存),而非在父类中缓存——因为父类是抽象的,无法直接作为 Bean 被 Spring 管理; - 避免在抽象类中使用 @Autowired 字段注入(违反依赖显式化原则,且抽象类无法被 Spring 实例化);
- 如需进一步减少 List 创建开销,可改造 Tesla 接口,提供 getSharedInventory() 方法,内部维护一个线程安全的缓存副本(例如 Supplier
- > cachedInventory = Suppliers.memoize(() -> fetchFromDB()))。
总结:共享对象的关键不在“父类存储”,而在于“统一注入同一单例 Bean”。通过构造函数将 Tesla 传入抽象父类,并由 Spring 容器统一管理其生命周期,即可自然实现多子类对同一底层服务实例的复用,从根本上规避内存冗余问题。








