gpt4 book ai didi

java - `ProvisionException` 被缓存并且构造函数代码永远不会重试

转载 作者:行者123 更新时间:2023-11-30 06:26:28 24 4
gpt4 key购买 nike

我有一个使用 PlayFramework 2.6.5 和 Guice DI (libraryDependency += guice) 构建的 Java Web 服务,只是在时间注入(inject)模式下。所有依赖项均通过构造函数注入(inject),使用 @Inject 和 @ImplementedBy ,并且 Guice Module 为空。

由于暂时性错误,某些依赖项可能会在构造函数中引发异常。发生这种情况时,服务会失败并出现 ProvisionException(这没关系,客户端应该重试)。

我发现这些异常被缓存,即使异常的根本原因得到解决,Play 或 Guice 也不会重试实例化这些类,并继续抛出相同的异常,直到 Web 服务重新启动。

例如,考虑以下类Clock,其构造函数在午夜 (00:xx) 时会失败。一旦系统时钟到达午夜,服务就无法实例化该类。当时钟到达凌晨 1 点时,同样的异常不断抛出。另外,异常消息始终相同(在示例中,异常消息是第一次发生异常的时间)

@ImplementedBy(OddClock.class)
public interface IClock {
//...
}

public class OddClock implements IClock {
@Inject
public OddClock() throws Exception {
if (DateTime.now().hourOfDay().get() == 0) {
throw new Exception(DateTime.now().toString());
}
}
}

public class TimeController {
@Inject
public TimeController(IClock clock) {
this.clock = clock;
}
}

顺便说一句,控制台应用程序也使用相同的代码库,它不会遇到这个问题,所以我认为 Play+Guice 集成有一些特别的地方。有什么建议可以关闭异常缓存吗?

最佳答案

抛出异常并缓存异常似乎是 Guice 中的内置行为。这也是一种公平的行为,因为 Guice 希望它创建的对象能够避免 IO 和其他非确定性操作。

https://github.com/google/guice/wiki/BeCarefulAboutIoInProviders

Provider doesn't define a retry-strategy. When a value is unavailable, calling get() multiple times may cause multiple failed provisions.

您可以通过更改您使用的范围来避免缓存,以便每次都重新创建实例。例如。使用 transient 作用域而不是单例。

在我看来,更好的解决方案是获取不可靠的对象并将其包装在另一个隐藏失败并处理重试的对象中。这样,当 Guice 尝试创建可靠对象时,它总是会成功,并且您可以在可靠包装器中添加自己的失败处理代码。

例如一个重试构造的简单示例:

public class ReliableClock { 
private Factory<Clock> clockFactory;
private Clock internalClock;
public ReliableClock(Factory<Clock> clockFactory) {
this.clockFactory = clockFactory;
}
private synchronized Clock currentClock() throws Exception {
if (clock == null) {
clock = clockFactory.create() // May throw exception
}
return clock;
}
// ... methods ...
}

关于java - `ProvisionException` 被缓存并且构造函数代码永远不会重试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47106044/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com