16

我一直想用我们的应用程序 + 构建系统在更大范围内尝试这个,但更高的优先级一直把它推到次要位置。这似乎是加载 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吗?

如果没有,请随意使用这个例子,看看它是如何为你工作的。(ServiceLoader 仅在 JDK6+ 中支持)

4

3 回答 3

3

我们在我的工作中几乎就是这样做的。由于一些内部限制,我们目前被困在 java 5 中,所以我们使用 Service Provider 做的有点不同(因为像你提到的那样在 java 6 之前无法访问 ServiceLocator),但它基本上是一样的。

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

于 2009-08-08T03:15:31.517 回答
1

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

我希望我的担忧是明确的。

于 2010-01-16T00:40:17.657 回答
0

“因为不可能两次绑定同一个接口。”

这确实是错误的!使用 Guice 的 Multibinder,有一种方法可以处理同一接口的不同实现,可能绑定在不同的模块中。

对于实际加载,我找到了一个与 Mark Renouf 略有不同的解决方案(他的 ModuleLoader 看起来确实更好),但我的博客文章可能会更多地展示这种方法适用的环境(插件)以及扩展点的样子:

Guice 2.0 Multibinder + Java ServiceLoader = 插件机制

于 2011-01-27T19:49:21.237 回答