使用 Provider 时如何将可配置参数传递给构造函数?
How to pass a configurable parameter to the constructor when using a Provider?
我最近在 Server
class 中添加了一个 Throttler
字段,只有在启用节流时才会实例化(这是一个配置条目),如果是这样,每秒最大请求数(另一个配置条目)将传递给它的构造函数。
这里是没有依赖注入的代码 Throttler
:
public class Server {
private Config config;
private Throttler throttler;
@Inject
public Server(Config config) {
this.config = config;
if (config.isThrottlingEnabled()) {
int maxServerRequestsPerSec = config.getMaxServerRequestsPerSec();
throttler = new Throttler(maxServerRequestsPerSec);
}
}
}
public class Throttler {
private int maxRequestsPerSec;
public Throttler(int maxRequestsPerSec) {
this.maxRequestsPerSec = maxRequestsPerSec
}
}
现在注入 Throttler
,我使用了 Provider
,因为它并不总是需要实例化。但是现在我被迫将 Config
注入 Throttler
并让它 "configure itself":
public class Server {
private Config config;
private Provider<Throttler> throttlerProvider;
@Inject
public Server(Config config, Provider<Throttler> throttlerProvider) {
this.config = config;
this.throttlerProvider = throttlerProvider;
if (config.isThrottlingEnabled()) {
this.throttler = throttlerProvider.get();
}
}
}
public class Throttler {
private int maxRequestsPerSec;
@Inject
public Throttler(Config config) {
maxRequestsPerSec = config.getMaxServerRequestsPerSec();
}
}
我不喜欢这个解决方案,因为:
- 实用程序 class (
Throttler
) 依赖于 Config
。
Throttler
现在绑定到一个特定的配置条目,这意味着它不能被除 Server
. 以外的其他任何东西使用
我更愿意以某种方式将 maxRequestsPerSec
注入构造函数。
Guice 可以吗?
这完全取决于您如何实现 Provider 接口以及您的应用程序。如果获取 maxRequestsPerSec 的唯一方法是从配置中获取,您可以按照以下方式执行操作:
您可以注入特定的 Provider 实现,并在其中包含一个 setter。因此,在您的构造函数中,您注入 CustomProvider<Throttler>
(实现 Provider
),然后执行 setMaxRequestsPerSec
,然后在实例化您的 Throttler 时在 get
方法中使用它。
如果您不想注入 CustomProvider
,您可以注入 Provider 然后进行 instanceof
检查,但我认为注入 CustomProvider 会更好。
Guice FAQ 建议引入一个工厂接口,该接口构建 class 及其依赖项和客户端传递的附加参数。
public class Throttler {
...
public static class Factory {
@Inject
public class Factory(... Throttler dependencies ...) {...}
public Throttler create(int maxRequestsPerSec) {
return new Throttler(maxRequestsPerSec /*, injected Throttler dependencies */);
}
}
}
这样,Throttler 的所有直接依赖项仍然封装在 Throttler 中 class。
您还可以使用 AssistedInject 扩展来减少样板代码。
我最近在 Server
class 中添加了一个 Throttler
字段,只有在启用节流时才会实例化(这是一个配置条目),如果是这样,每秒最大请求数(另一个配置条目)将传递给它的构造函数。
这里是没有依赖注入的代码 Throttler
:
public class Server {
private Config config;
private Throttler throttler;
@Inject
public Server(Config config) {
this.config = config;
if (config.isThrottlingEnabled()) {
int maxServerRequestsPerSec = config.getMaxServerRequestsPerSec();
throttler = new Throttler(maxServerRequestsPerSec);
}
}
}
public class Throttler {
private int maxRequestsPerSec;
public Throttler(int maxRequestsPerSec) {
this.maxRequestsPerSec = maxRequestsPerSec
}
}
现在注入 Throttler
,我使用了 Provider
,因为它并不总是需要实例化。但是现在我被迫将 Config
注入 Throttler
并让它 "configure itself":
public class Server {
private Config config;
private Provider<Throttler> throttlerProvider;
@Inject
public Server(Config config, Provider<Throttler> throttlerProvider) {
this.config = config;
this.throttlerProvider = throttlerProvider;
if (config.isThrottlingEnabled()) {
this.throttler = throttlerProvider.get();
}
}
}
public class Throttler {
private int maxRequestsPerSec;
@Inject
public Throttler(Config config) {
maxRequestsPerSec = config.getMaxServerRequestsPerSec();
}
}
我不喜欢这个解决方案,因为:
- 实用程序 class (
Throttler
) 依赖于Config
。 Throttler
现在绑定到一个特定的配置条目,这意味着它不能被除Server
. 以外的其他任何东西使用
我更愿意以某种方式将 maxRequestsPerSec
注入构造函数。
Guice 可以吗?
这完全取决于您如何实现 Provider 接口以及您的应用程序。如果获取 maxRequestsPerSec 的唯一方法是从配置中获取,您可以按照以下方式执行操作:
您可以注入特定的 Provider 实现,并在其中包含一个 setter。因此,在您的构造函数中,您注入 CustomProvider<Throttler>
(实现 Provider
),然后执行 setMaxRequestsPerSec
,然后在实例化您的 Throttler 时在 get
方法中使用它。
如果您不想注入 CustomProvider
,您可以注入 Provider 然后进行 instanceof
检查,但我认为注入 CustomProvider 会更好。
Guice FAQ 建议引入一个工厂接口,该接口构建 class 及其依赖项和客户端传递的附加参数。
public class Throttler {
...
public static class Factory {
@Inject
public class Factory(... Throttler dependencies ...) {...}
public Throttler create(int maxRequestsPerSec) {
return new Throttler(maxRequestsPerSec /*, injected Throttler dependencies */);
}
}
}
这样,Throttler 的所有直接依赖项仍然封装在 Throttler 中 class。
您还可以使用 AssistedInject 扩展来减少样板代码。