静态依赖注入 VS 动态依赖查询

一、一句话定义

方式 核心特征 通俗理解
静态依赖注入 Spring 自动把依赖塞进来 食堂阿姨给你打饭,你坐着等就行
动态依赖查找 你主动去容器里找 Bean 自助餐,你自己起身去拿

二、静态依赖注入(Static Dependency Injection)

代码长这样

java 复制代码
@Service
public class OrderService {
    
    // 方式1:字段注入(最常见)
    @Autowired
    private UserService userService;
    
    // 方式2:构造方法注入(Spring 推荐)
    public OrderService(UserService userService) {
        this.userService = userService;
    }
    
    // 方式3:Setter 注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

特点

  • 启动时就定死了:Spring 扫描到 @Autowired,启动阶段就会把 UserService 的对象注入进来。

  • 你完全不用管:依赖怎么来的、什么时候创建的,你都不关心。

  • 依赖关系明确 :看一眼代码,就知道 OrderService 依赖 UserService。


三、动态依赖查找(Dynamic Dependency Lookup)

代码长这样

java 复制代码
@Service
public class OrderService implements ApplicationContextAware {
    
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        this.context = ctx;
    }
    
    public void createOrder(String type) {
        // 运行时,根据参数动态去容器里"查找"对应的 Bean
        PaymentStrategy strategy = context.getBean(type + "Strategy", PaymentStrategy.class);
        strategy.pay();
    }
}

或者更直接的:

java 复制代码
@Autowired
private ApplicationContext context;

public void doSomething() {
    // 需要的时候才去"拿"
    UserService userService = context.getBean(UserService.class);
}

特点

  • 运行时才能确定:代码写的时候不知道要拿哪个 Bean,运行时才决定。

  • 你主动伸手 :不是 Spring 塞给你,是你主动 getBean()。

  • 耦合了 Spring 容器 :你的代码里出现了 ApplicationContext,离开 Spring 框架这段代码就没法跑了。


四、核心区别对比

对比项 静态依赖注入 动态依赖查找
代码写法 @Autowired、构造方法 context.getBean(...)
时机 容器启动时注入 运行时按需查找
依赖是否明确 明确,写死在代码里 不明确,运行时动态决定
是否耦合 Spring 不耦合(注解可被其他框架识别) 强耦合 ApplicationContext
灵活性 低,依赖固定 高,可以动态切换
可测试性 好,直接 Mock 依赖 差,需要模拟 Spring 容器
典型场景 绝大多数日常开发 策略模式、插件化、工厂模式

五、为什么需要"动态依赖查找"?

你可能会问:静态注入这么好用,为什么还要主动 getBean()?

场景 1:策略模式(运行时决定用哪个实现)

java 复制代码
@Service
public class PayFactory implements ApplicationContextAware {
    
    private ApplicationContext context;
    
    public void pay(String channel) {  // channel = "alipay" 或 "wechat"
        // 启动时不知道用户会选哪种支付方式,只能运行时去查
        PaymentService service = context.getBean(channel + "PayService", PaymentService.class);
        service.pay();
    }
}

这里你不可能 写 @Autowired,因为启动时不知道用户会传 "alipay" 还是 "wechat"。

场景 2:解决循环依赖(应急方案)

java 复制代码
@Service
public class A {
    
    @Autowired
    private ApplicationContext context;
    
    // 构造方法注入会导致循环依赖时,可以延迟查找
    public void doSomething() {
        B b = context.getBean(B.class);  // 用的时候才拿,打破循环
        b.doSomething();
    }
}

场景 3:获取非单例 Bean(Prototype)

复制代码
// 每次都需要一个新的对象
TaskExecutor executor = context.getBean(TaskExecutor.class);

六、面试常问:ApplicationContextAware 属于哪种?

标准答案:

ApplicationContextAware 本身是 Aware 接口回调 (属于生命周期钩子),但它赋予了你"动态依赖查找"的能力。

也就是说:

  • 实现 ApplicationContextAware → 是为了拿到 Spring 容器

  • 拿到容器后调用 getBean() → 这就是动态依赖查找

面试官追问 :既然能动态查找,是不是所有依赖都用 getBean() 更好?

答 :不是。能用静态注入的,绝对不要用动态查找。因为:

  1. 代码耦合 Spring 容器,不好单元测试

  2. 隐藏了类的依赖关系,代码可读性差

  3. 违背了"控制反转"的初衷(IoC 就是让你被动接收,而不是主动索取)


七、一张图记住

复制代码
【Spring 容器】
     │
     ├─ 静态注入 ──→ Spring 主动推给你 ──→ @Autowired
     │                  "你坐着,饭送嘴边"
     │
     └─ 动态查找 ──→ 你主动找容器要 ──→ getBean()
                        "你自己去窗口端菜"

八、总结

你的情况 用哪个
依赖关系明确,启动时就知道要谁 静态注入 @Autowired
运行时才能确定要哪个 Bean 动态查找 getBean()
写框架、做插件化、策略工厂 可以用动态查找
写普通业务代码 只用静态注入,别碰 getBean()

记住一个原则:动态查找是"杀手锏",不是"日常武器"。 日常开发里看到有人到处 getBean(),通常说明代码设计有问题。

相关推荐
Joy T6 小时前
Spring AI 项目中的 pom.xml、application.yml 与 Nacos:从依赖管理到运行配置
spring·nacos·pom.xml·profile·参数配置·application.yml
fundoit13 小时前
为什么需要 Access Token 和 ID Token 两个令牌
java·spring·架构·github·oauth2
鱼宵13 小时前
Spring AI 流式输出:Flux + SSE 打字机,回答不再干等三秒
java·人工智能·spring·sse·springai·流式输出
小鹿的周先生14 小时前
第19章-Agent
java·spring·ai
步行cgn15 小时前
MySQL 报错:Access denied for user ‘root‘@‘localhost‘ 详解
java·数据库·spring
鱼宵16 小时前
Spring AI 生产化改造:记忆落 Redis、向量落 ES,重启再也不丢
人工智能·redis·spring·elasticsearch·springai
Wang's Blog16 小时前
Java框架 SpringCloud 快速入门: Nacos 配置热更新
java·spring·spring cloud
天空鸟_时光不老18 小时前
06-给AI流程加一道人工闸门
java·人工智能·spring boot·后端·spring·spring cloud·架构
阿俊-全栈开发18 小时前
LikeShop单商户Java商城如何从容承接高并发流量?
java·开发语言·spring boot·spring·系统架构
天空鸟_时光不老18 小时前
01-我不转Python把AI塞进Java里
java·人工智能·spring boot·后端·spring·spring cloud·架构