Has anyone used ServiceLoader together with Guice?

放肆的年华 提交于 2019-12-20 08:51:19

问题


I keep wanting to try this on a larger scale with our app + build system, but higher priorities keep pushing it to the back burner. It seems like a nice way to load Guice modules and avoids the common complaint about "hard coded configuration". Individual configuration properties rarely change on their own, but you will almost always have a set of profiles, usually for different environments (Debug, Production, etc).

ServiceLoader lets you pull a list of all implementations defined as a service for a given type. Putting this together with Guice, you end up with:

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);
        }
    }
}

Usage example (as a dynamic servlet loader in a guice-servlet project):

import com.google.inject.servlet.ServletModule;

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

The services (packaged as modules) would be packaged in seperate jar files. Within each one you'd define the class(es) in the meta-data:

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

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

Since we use Maven, we think this would be ideal as we could pull in different implementations at runtime via profile dependencies. Is anyone using Guice like this?

If not, feel free to use this example and see how it works for you. (ServiceLoader is only supported in JDK6+)


回答1:


We're doing almost exactly this at my work. We're currently stuck in java 5 due to some internal limitations, so we do it a bit differently using Service Provider (due to not having access to ServiceLocator until java 6 like you mentioned), but it essentially works the same.

I remember reading somewhere that this was one of the preferred ways the Guice developers recommended, though they want to leave this open for flexibility.




回答2:


I considered this way already but i didnt use it because i was afraid, that i have to keep my modules extremely small, because its impossible to bind the same interface twice. My problem is, that if i want to use an interface/class/enum/whatever from another jar and that jar defined a services/* file i am screwed, because i cant make use of the content of the jar without loading it as a module.

I hope my concern is clear.




回答3:


"because its impossible to bind the same interface twice."

This is indeed wrong! With Guice's Multibinder there is a way to work with different implementations of the same interface, possibly bound in different modules.

I came to a slightly different solution for the actual loading than Mark Renouf (his ModuleLoader looks indeed better), but my blog post may show a bit more about the environment where this approach is applicable (Plugins) and what the extension points look like:

Guice 2.0 Multibinder + Java ServiceLoader = Plugin mechanism



来源:https://stackoverflow.com/questions/902639/has-anyone-used-serviceloader-together-with-guice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!