如果没有一些昂贵的类路径扫描,这将是不可能的:如果注入器没有对您的 Twix 类的任何引用,它就无法在不扫描类路径上的每个 JAR 的情况下将其绑定到 Map 中@SnackImpl
-带注释的类。您可以尝试使用Guava 的 ClassPath,但如果您使用基于网络或自定义的类加载器,这可能根本无法处理。无论如何,我不会推荐它。
一种替代方法是使用 Java 的内置ServiceLoader框架,该框架允许各个 JAR 列出给定服务(接口)的完全合格的实现。您甚至可以使用 Google 的 Auto 框架根据注释为您生成该服务文件。
这需要列出实现,但您仍然需要将它们绑定到 MapBinder。幸运的是,MapBinder 不需要单个定义,并且会在模块构建期间自动合并多个 MapBinder 定义:
支持从不同模块贡献映射绑定。例如,可以让 CandyModule 和 ChipsModule 都创建自己的 MapBinder,并各自为小吃地图提供绑定。注入该映射后,它将包含来自两个模块的条目。
(来自MapBinder 文档)
考虑到这一点,我建议每个插件包都有自己的 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 没有的绑定的任何分散化还没给你。