【问题标题】:Is it possible to have a constant valued through a Spring Service?是否可以通过 Spring Service 获得常量值?
【发布时间】:2017-08-23 03:15:57
【问题描述】:

我们有一个 Web 服务,其中一个参数称为源,并且该源始终根据数据库中的代码进行验证。

对于我们的每一项服务,我都必须验证此代码。这段代码不会改变,所以我想保持不变,但我仍然需要验证它以防止客户端发送错误的代码。

基本上我想要的是这样的:

@Service
public class Service {

    @Autowired
    private LogBS logBS;

    // I know this cannot be used in a static context.
    public static final Long CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");

    public void validateOriginCode(final Long origin) {
        if (!origin.equals(CODE)) {
            throw new ServiceException("Wrong origin code!");
       }
   }
}

我知道使用 Spring 缓存可以做类似的事情,但是可以用常量来做吗?

【问题讨论】:

  • 为什么不创建一个不可变的类来保存常量并在Service 类的@PostConstruct 中初始化它?
  • @yaswanth 你能发布一个答案吗?

标签: spring web-services static singleton


【解决方案1】:

我宁愿这样做:

@Service
public class CodeValidatorService {

    private LogBS logBS;

    private Long CODE;

    @Autowired
    public CodeValidatorService(LogBS logBS){
        this.logBS = logBS;
        CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
        if (CODE == null){
            throw new ServiceException("Code cannot be read from DB!");
        }
    }

    public void validateOriginCode(final Long origin) {
        if (!origin.equals(CODE)) {
            throw new ServiceException("Wrong origin code!");
       }
   }
}

就像代码审查一样,我更喜欢在构造函数中注入依赖项而不是直接在字段中使用@Autowired,它使服务可测试。您也可以尝试在 @PostConstruct 方法中读取代码,但我认为最好在构造函数中执行此操作,这样您的服务始终处于准备就绪状态。

要在您的其余服务中使用它,请在它们上注入 CodeValidatorService 实例:

@Service
public class OtherService {

    private CodeValidatorService codeValidatorService;

    @Autowired
    public OtherService(CodeValidatorService codeValidatorService){
        this.codeValidatorService = codeValidatorService;
    }

    public void performAction(final Long origin) {
        codeValidatorService.validateOriginCode(origin);
        //do the rest of your logic here
   }
}

另请参阅:

【讨论】:

  • 这样我就无法为所有其他@Services 提供代码。
  • 答案已更改。
  • 很好的答案。由于 Spring Beans 是 Singletons,我将只执行一次查询,因为我打算使用构造函数方法自动装配依赖项。我也会将我的属性与 final 关键字一起使用。
  • 是的,就是这样。对我来说,将 Spring 用于单例而不是自己实现单例的最好的事情是您可以轻松地测试它们(例如,使用此实现来模拟 CodeValidatorService 很容易,以强制它返回异常)并且 impl 是更具可读性。
  • 出于几个原因,我个人不再在没有 Spring 的情况下编写代码。代码可读性和可测试性是其中两个。
【解决方案2】:

你可以有一个 constantsProvider 类

@Component
public class ConstantsProvider {

    @Autowired
    private LogBS logBS;

    private String CODE;

    @PostConstruct
    public void init() {
        CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
    }

    public String getCode() {
        return CODE;
    }
}

将此代码的 sn-p 添加到 Service

@Autowired
private ConstantsProvider constantsProvider;

您可以在服务中使用constantsProvider.getCode()。这样 CODE 将是不可变的,并且不会在静态上下文中定义。

注意:如果你有更多类似的常量,有更好的方法来定义ConstantsProvider 类。如果只有一个,我会坚持上面的实现。

编辑 1:

如果您在所有服务类中都需要它,请将 constantsProvider 设为 spring bean 并在那里初始化 CODE。更新了答案

【讨论】:

  • 这种方式必须在所有服务中编写 init 方法,或者必须考虑某种服务层次结构。定义 ConstantsProvider 的更好方法是什么?
  • 更新了答案
  • 与接受的答案基本相同。
  • 是的。接受的答案似乎更好。我发现问题不够清楚,您需要在所有服务中都有这个常量。
  • 我仍然感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2018-10-25
  • 2015-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多