gpt4 book ai didi

java - Guice、设置和样板代码

转载 作者:搜寻专家 更新时间:2023-11-01 03:25:26 25 4
gpt4 key购买 nike

我有一个应用程序使用 Guice 并从配置文件中读取一些配置设置。我这样加载它:

@Provides @Singleton
Settings provideSettings() {
// code that loads the settings
}

某些对象需要某些设置,其他对象需要其他设置。在我看来,在构造函数中传递这些东西是有意义的,但后来我得到了很多样板代码,例如:

@Provides @Named("integerValueSetting1")
int provideIntegerValueSetting1(Settings settings) {
return settings.getInteger("integerValueSetting1");
}

而且我必须为每个设置类型创建这样一个@Provides 方法,另外我还必须在构造函数中注释适当的设置。像这样:

@Inject
public MyClass(@Assisted String objectName, @Named("integerValueSetting1") myValue) {
// blah blah constructor
}

这似乎并没有节省我多少时间!更糟糕的是,如果我为每个设置参数创建一个自定义注释类。一定有更好的方法,对吧?

一种解决方案是直接传递设置对象,但这违反了 best practices: Inject only direct dependencies ...

最佳答案

如果您有大量设置,并且希望避免为每个设置创建新的绑定(bind)注释,您可以尝试将它们放在一个枚举中并在一个公共(public)绑定(bind)注释中使用该枚举。这可能是一个有点复杂的解决方案,但它也可以节省您试图避免的样板文件。

通过这种方式,您可以匹配对象引用(IDE 友好)而不是字符串(缓慢且脆弱),并且仍然只创建一个绑定(bind)注释。

public enum Config {
DB_NAME("db_name"),
DB_HOST("db_host_name_specified_in_file"),
SOME_NUMBER("some_number"),
;

private final String propertyName;

private Config(String propertyName) {
this.propertyName = propertyName;
}

public String getPropertyName() {
return propertyName;
}

public InjectConfig annotation() {
// Create an implementation of InjectConfig for ease of binding.
return new InjectConfig() {
@Override public Class<? extends Annotation> annotationType() {
return InjectConfig.class;
}

@Override public Config value() {
return Config.this;
}

@Override public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (!(obj instanceof InjectConfig)) {
return false;
}
return value() == ((InjectConfig) obj).value();
}

/** @see Annotation#hashCode */
@Override public int hashCode() {
return (127 * "value".hashCode()) ^ value().hashCode();
}
};
}

@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
public static @interface InjectConfig {
Config value();
}
}

现在您可以遍历并在一个循环中绑定(bind)每一个:

public class YourModule extend AbstractModule {
@Override public void configure() {
// You can get a Provider in a Module as long as you
// don't call get() before the injector exists.
Provider<Settings> settingsProvider = binder().getProvider(Settings.class);
for (Config config : Config.values()) {
String propertyName = config.getPropertyName();
// Guice's TypeConverter will convert Strings to the right type.
bind(String.class).annotatedWith(config.annotation()).toProvider(
new GetValueFromSettingsProvider(settingsProvider, propertyName));
}
}
}

然后只注入(inject)你需要的,直接:

/** Your constructor */
YourClass(@InjectConfig(DB_USER) String user,
@InjectConfig(SOME_NUMBER) int number) { }

我没有机会对此进行测试,但据我所知,它应该可以工作。鉴于您的特定设置用例,您可能需要修改您编写的 GetValueFromSettingsProvider,或者在枚举中编写可重写的 getConfigValueFromSettings 方法。不过请记住,不管怎样,您仍然需要存储(枚举键、文件中的属性名称、属性类型)元组,而且 Enum 似乎是以编程方式管理它的最佳方式。

关于java - Guice、设置和样板代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15146467/

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