有没有人将ServiceLoader与Guice一起使用?

2022-09-03 08:05:23

我一直想用我们的应用程序+构建系统更大规模地尝试这一点,但更高的优先级不断将其推到次要位置。这似乎是加载Guice模块的好方法,并避免了关于“硬编码配置”的常见抱怨。单个配置属性很少会自行更改,但您几乎总是有一组配置文件,通常用于不同的环境(调试、生产等)。

ServiceLoader 允许您提取定义为给定类型的服务的所有实现的列表。把这个和Guice放在一起,你最终会得到:

import java.util.ServiceLoader;

import com.google.inject.AbstractModule;
import com.google.inject.Module;

public class ModuleLoader<M extends Module> extends AbstractModule {

    private final Class<M> type;

    public ModuleLoader(Class<M> type) {
        this.type = type;
    }

    public static <M extends Module> ModuleLoader<M> of(Class<M> type) {
        return new ModuleLoader<M>(type);
    }

    @Override
    protected void configure() {
        ServiceLoader<M> modules = ServiceLoader.load(type);
        for (Module module : modules) {
            install(module);
        }
    }
}

使用示例(作为 guice-servlet 项目中的动态 servlet 加载程序):

import com.google.inject.servlet.ServletModule;

public class ServletLoader extends GuiceServletContextListener {
    @Override
    protected final Injector getInjector() {
       return Guice.createInjector(ModuleLoader.of(ServletModule.class);
    }
}

服务(打包为模块)将打包在单独的 jar 文件中。在每个类中,您都可以在元数据中定义类:

Within servlets.jar: META-INF/services/com.google.inject.Module

com.example.webapps.MyServletModuleA
com.example.webapps.MyServletModuleB

由于我们使用Maven,我们认为这将是理想的,因为我们可以通过配置文件依赖项在运行时引入不同的实现。有人像这样使用Guice吗?

如果没有,请随时使用此示例,看看它如何为您工作。(只有 JDK6+ 支持 ServiceLoader)


答案 1

在我的工作中,我们几乎完全在做这件事。由于一些内部限制,我们目前被困在java 5中,所以我们使用Service Provider的方式略有不同(因为像你提到的java 6之前无法访问ServiceLocator),但它基本上工作原理相同。

我记得在某处读到,这是Guice开发人员推荐的首选方式之一,尽管他们希望保持这种灵活性。


答案 2

我已经考虑过这种方式,但我没有使用它,因为我害怕,我必须保持我的模块非常小,因为它不可能将同一接口绑定两次。我的问题是,如果我想使用另一个jar中的接口/类/enum/任何东西,并且该jar定义了一个services/ *文件,我就搞砸了,因为我不能在不将其作为模块加载的情况下使用jar的内容。

我希望我的关切是明确的。


推荐