代码之家  ›  专栏  ›  技术社区  ›  itsadok

有人和guice一起使用serviceloader吗?

  •  14
  • itsadok  · 技术社区  · 15 年前

    我一直想用我们的app+build系统在更大的范围内尝试这个,但是更高的优先级一直把它推到次要位置。这似乎是加载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+中受支持)

    3 回复  |  直到 13 年前
        1
  •  3
  •   bkdougan    15 年前

    我们在我的工作中几乎就是这样做的。由于一些内部限制,我们目前停留在Java 5中,所以我们使用服务提供者的方式有点不同(因为没有像前面提到的Java 6那样访问Service Loopor),但它本质上是相同的。

    我记得在某个地方读过,这是Guice开发人员推荐的一种首选方式,尽管他们想让这个开放性保持灵活性。

        2
  •  1
  •   whiskeysierra    15 年前

    我已经考虑过这种方式,但我没有使用它,因为我害怕,我必须保持我的模块非常小,因为它不可能绑定相同的界面两次。我的问题是,如果我想使用另一个jar中的interface/class/enum/whatever,而这个jar定义了一个services/*文件,我就麻烦了,因为如果不将jar的内容作为模块加载,我就无法使用它。

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

        3
  •  0
  •   Det    14 年前

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

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

    与mark renouf(他的moduleloader看起来确实更好)相比,我找到了一个实际加载的稍微不同的解决方案,但是我的博客文章可能会更多地展示这种方法适用的环境(插件)以及扩展点的样子:

    Guice 2.0 Multibinder + Java ServiceLoader = Plugin mechanism