在Java项目中,使用Google Guice使用Gradle 5.2进行构建。
我使用MapBinder
(http://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/multibindings/MapBinder.html):
MapBinder<String, Snack> mapbinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapbinder.addBinding("twix").toInstance(new Twix());
mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
mapbinder.addBinding("skittles").to(Skittles.class);
这项工作正常,但是现在,我需要一个“插件体系结构”,因此避免导入所有Snack类,而是直接在类中声明它,例如:
@SnackImpl("Twix")
class Twix extends Snack {
}
怎么样?
最佳答案
没有一些昂贵的类路径扫描,这将是完全不可能的:如果注入器没有对您的Twix类的任何引用,那么如果不对类路径中的每个JAR进行扫描以寻找注释的类。您可以使用Guava's ClassPath尝试此操作,但是如果您使用基于网络的或自定义的类加载器,则可能根本无法处理。无论如何,我都不会推荐它。
一种替代方法是使用Java的内置ServiceLoader框架,该框架允许各个JAR列出给定服务(接口)的标准实现。您甚至可以使用Google的Auto框架基于注释generate that service file for you。
这样就可以列出实现,但是您仍然需要将它们绑定到MapBinder中。幸运的是,MapBinder不需要单个定义,并且会在模块构建期间自动合并多个MapBinder定义:
支持从不同模块提供映射绑定。例如,可以使CandyModule和ChipsModule都创建自己的MapBinder,并为小吃地图贡献绑定。当该映射被注入时,它将包含来自两个模块的条目。
(来自MapBinder docs)
考虑到这一点,我建议每个插件包都获得一个自己的Guice模块,并在其中注册到MapBinder中,然后使用ServiceLoader将这些Guice模块添加到主注射器中,以在注射器创建时获取这些模块。
// Assume CandyPluginModule extends AbstractModule
@AutoService(CandyPluginModule.class)
public TwixPluginModule extends CandyPluginModule {
@Override public void configure() {
MapBinder<String, Snack> mapBinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapBinder.addBinding("twix").to(Twix.class);
}
}
您还可以利用超类:
@AutoService(CandyPluginModule.class)
public TwixPluginModule extends CandyPluginModule {
@Override public void configureSnacks() { // defined on CandyPluginModule
bindSnack("twix").to(Twix.class);
}
}
或者,您可以直接使用AutoService列出Twix之类的实现,然后创建一个模块,将所有ServiceLoader实现读取到MapBinder中,但是这可能会限制插件的灵活性,并且不会像MapBinder那样使您分散绑定还没有给你。
关于java - 使用注释来馈送Google guice MapBinder,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54914013/