You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring:如何在@ControllerAdvice注解的类中使用注入的Service?

问题原因

  • 核心原因是@RefreshScope与@ControllerAdvice的加载优先级、代理逻辑存在冲突:
    @RefreshScope是Spring Cloud提供的动态刷新作用域,被其标记的Bean会被封装为CGLIB代理对象,默认懒加载,只有第一次调用时才会完成实例化和依赖注入。而@ControllerAdvice作为全局异常处理器,会在Spring MVC上下文启动的极早阶段被扫描注册,此时@RefreshScope代理还未完成初始化,构造器注入的依赖没有被赋值,就会出现null的情况。
  • 次要原因是@RequiredArgsConstructor与CGLIB代理的兼容问题:
    CGLIB生成代理类时要求目标类有可访问的无参构造方法,而@RequiredArgsConstructor只会生成包含final字段参数的构造方法,没有无参构造,导致代理实例化失败,最终字段为空。
  • 小概率原因是上下文隔离问题:如果你的项目存在父子上下文分层,SomeService注册在Spring MVC子上下文,而@ControllerAdvice被父上下文扫描,也会出现注入失败,但该情况下SomeService在其他父上下文的Bean中也无法调用,和你的描述不符,可以优先排除。

解决方案

方案1(最推荐):移除@ControllerAdvice类上的@RefreshScope

绝大多数场景下全局异常处理器不需要动态刷新配置,直接移除@RefreshScope注解即可解决初始化顺序问题,修改后代码如下:

@ControllerAdvice
@Slf4j
@RequiredArgsConstructor
public class ExceptionHandlerController {
    private final SomeService someService;
    // 其余逻辑不变
}

如果你的业务需要动态刷新配置,将@RefreshScope移到对应的配置类或者SomeService类上即可,不需要加在异常处理器本身。

方案2:保留@RefreshScope,改用懒加载注入

如果确实需要给异常处理器开启动态刷新,将构造器注入改为带@Lazy注解的字段注入,延迟依赖的加载时机,等代理初始化完成后再注入:

@ControllerAdvice
@Slf4j
@RefreshScope
public class ExceptionHandlerController {
    @Autowired
    @Lazy
    private SomeService someService;
    // 其余逻辑不变
}

方案3:补充无参构造方法兼容CGLIB代理

要兼容@RequiredArgsConstructor和CGLIB代理,手动补充一个protected权限的无参构造方法给代理实例化使用:

@ControllerAdvice
@Slf4j
@RequiredArgsConstructor
@RefreshScope
public class ExceptionHandlerController {
    private final SomeService someService;
    
    // 仅供CGLIB生成代理使用
    protected ExceptionHandlerController() {
        this.someService = null;
    }
    // 其余逻辑不变
}

内容的提问来源于stack exchange,提问作者Simon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 20:24:06