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

如何在自定义异常的单参构造中使用@Autowired注入的MessageSource?

这个问题我之前也碰到过,核心原因其实是Spring容器只会管理它自己创建的Bean,你通过new关键字手动实例化的MyBusinessException对象不在Spring的管辖范围内,所以@Autowired注入的MessageSource必然是null,构造注入和@PostConstruct自然也起不了作用。下面给你两种可行的解决方案,按需选择:

方案1:用Spring上下文工具类直接获取MessageSource

这种方式最直接,不需要额外的工厂类,通过一个静态工具类拿到Spring容器里的MessageSource实例:

首先创建一个Spring上下文工具类,让它实现ApplicationContextAware接口来获取容器上下文:

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextHelper implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHelper.context = applicationContext;
    }

    public static <T> T getBean(Class<T> beanType) {
        return context.getBean(beanType);
    }
}

然后修改你的异常类,去掉@Autowired的MessageSource字段,在构造方法里通过工具类获取实例:

import org.springframework.context.MessageSource;
import java.util.Locale;

public class MyBusinessException extends RuntimeException {
    private String errorCode;
    private String messageInEnglish;

    public MyBusinessException(String errorCode) {
        this.errorCode = errorCode;
        // 从Spring容器获取MessageSource
        MessageSource messageSource = SpringContextHelper.getBean(MessageSource.class);
        this.messageInEnglish = messageSource.getMessage(errorCode, null, Locale.ENGLISH);
        // 把英文消息设置为父类的message,这样抛出异常时能直接看到内容
        super(this.messageInEnglish);
    }

    // 添加上getter方法方便外部获取
    public String getErrorCode() {
        return errorCode;
    }

    public String getMessageInEnglish() {
        return messageInEnglish;
    }
}

现在你就可以直接用throw new MyBusinessException("MY-ERROR-CODE");来实例化异常,它会自动从MessageSource里加载对应的英文错误消息。

方案2:用异常工厂类(更符合Spring设计思想)

如果想避免静态工具类的依赖,让代码更符合Spring的依赖注入原则,可以创建一个由Spring托管的工厂类,专门负责创建MyBusinessException实例:

首先写工厂类,注入MessageSource:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
import java.util.Locale;

@Component
public class BusinessExceptionFactory {
    private final MessageSource messageSource;

    @Autowired
    public BusinessExceptionFactory(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    // 创建指定errorCode的异常,默认加载英文消息
    public MyBusinessException create(String errorCode) {
        String englishMessage = messageSource.getMessage(errorCode, null, Locale.ENGLISH);
        return new MyBusinessException(errorCode, englishMessage);
    }

    // 可选:支持根据当前请求的Locale加载消息(如果是Web项目)
    public MyBusinessException createWithCurrentLocale(String errorCode) {
        Locale currentLocale = org.springframework.context.i18n.LocaleContextHolder.getLocale();
        String message = messageSource.getMessage(errorCode, null, currentLocale);
        return new MyBusinessException(errorCode, message);
    }
}

然后修改异常类,把构造方法设为私有,只允许工厂类创建实例:

public class MyBusinessException extends RuntimeException {
    private String errorCode;
    private String messageInEnglish;

    // 私有构造方法,外部不能直接new
    private MyBusinessException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
        this.messageInEnglish = message;
    }

    // getter方法
    public String getErrorCode() {
        return errorCode;
    }

    public String getMessageInEnglish() {
        return messageInEnglish;
    }
}

使用的时候,在Spring托管的Bean(比如Service、Controller)里注入工厂类即可:

import org.springframework.stereotype.Service;

@Service
public class YourBusinessService {
    private final BusinessExceptionFactory exceptionFactory;

    @Autowired
    public YourBusinessService(BusinessExceptionFactory exceptionFactory) {
        this.exceptionFactory = exceptionFactory;
    }

    public void doBusinessLogic() {
        // 抛出异常
        throw exceptionFactory.create("MY-ERROR-CODE");
    }
}

两种方案对比

  • 方案1:实现简单,直接就能用,适合快速解决问题;但依赖静态工具类,单元测试时需要模拟Spring上下文,稍微麻烦一点。
  • 方案2:更符合Spring的依赖注入理念,代码解耦更好,单元测试时可以轻松MockMessageSource或者工厂类,适合中大型项目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:56:07