我最近在Throttler类中添加了一个Server字段,该字段仅在启用节流(这是一个配置项)时实例化,如果是,则每秒的最大请求数(另一个配置项)为传递给它的构造函数。

这是没有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并让其“自行配置”:

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();
    }
}


我不喜欢这种解决方案,因为:


实用程序类(Throttler)对Config有依赖性。
现在,Throttler已绑定到特定的配置条目,这意味着除Server之外,其他任何物品都不能使用它。


我宁愿以某种方式将maxRequestsPerSec注入构造函数。

Guice有可能吗?

最佳答案

Guice FAQ建议引入一个工厂接口,该接口使用其依赖项和客户端传递的其他参数来构建类。

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 */);
        }
    }
}


这样,Throtler的所有直接依赖项都封装在Throttler类中。

您也可以使用AssistedInject扩展名来减少样板代码。

10-07 12:58