【问题标题】:Guice don't inject to Jersey's resourcesGuice 不会注入泽西岛的资源
【发布时间】:2016-05-07 05:34:30
【问题描述】:

在整个互联网上进行了解析,但无法弄清楚为什么会发生这种情况。我有一个带有 Jersey 资源的最简单的项目(通过 jersey-quickstart-grizzly2 原型)。我将 Guice 用作 DI,因为 CDI 也不想与 Jersey 合作。问题是 Guice 在注入 Jersey 的资源时无法解析要使用的类。它在外面很好用,但不适用于泽西岛。 这是泽西岛资源:

import com.google.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("api")
public class MyResource {

    private Transport transport;

    @Inject
    public void setTransport(Transport transport) {
        this.transport = transport;
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getIt() {
        return transport.encode("Got it!");
    }
}

传输接口:

public interface Transport {
    String encode(String input);
}

这是实现:

public class TransportImpl implements Transport {
    @Override
    public String encode(String input) {
        return "before:".concat(input).concat(":after");
    }
}

按照 Google 的 GettingStarted 手册,我继承了 AbstractModule 并像这样绑定我的类:

public class TransportModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Transport.class).to(TransportImpl.class);
    }
}

我用这个在main() 得到注射器,但这里并不需要它:

Injector injector = Guice.createInjector(new TransportModule());

顺便说一句,当我尝试这样做时没有问题:

Transport transport = injector.getInstance(Transport.class);

【问题讨论】:

    标签: java rest dependency-injection jersey guice


    【解决方案1】:

    Jersey 2 已经有一个 DI 框架,HK2。您可以使用它,或者如果需要,您可以使用 HK2/Guice 桥接器将您的 Guice 模块与 HK2 结合。

    如果您想使用 HK2,在最基本的层面上,它与 Guice 模块没有太大区别。例如,在您当前的代码中,您可以这样做

    public class Binder extends AbstractBinder {
        @Override
        public void configurer() {
            bind(TransportImpl.class).to(Transport.class);
        }
    }
    

    然后只需向 Jersey 注册活页夹

    new ResourceConfig().register(new Binder());
    

    一个区别是绑定声明。在 Guice 中,它“将合同与实施绑定”,而在 HK2 中,它是“将实施与合同绑定”。您可以看到它与 Guice 模块相反。

    如果您想桥接 Guice 和 HK2,那就稍微复杂一点。你需要对HK2多了解一点。这是一个如何让它工作的例子

    @Priority(1)
    public class GuiceFeature implements Feature {
    
        @Override
        public boolean configure(FeatureContext context) {
            ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
            GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
            Injector injector = Guice.createInjector(new TransportModule());
            GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
            guiceBridge.bridgeGuiceInjector(injector);
            return true;
        }
    } 
    

    然后注册功能

    new ResourceConfig().register(new GuiceFeature());
    

    如果您打算使用 Jersey,我个人建议您熟悉 HK2。

    另请参阅:


    更新

    对不起,我忘记添加要使用Guice Bridge,您需要依赖。

    <dependency>
        <groupId>org.glassfish.hk2</groupId>
        <artifactId>guice-bridge</artifactId>
        <version>2.4.0-b31</version>
    </dependency>
    

    请注意,这是 Jersey 2.22.1 的依赖项。如果您使用不同版本的 HK2,请确保使用与您的 Jersey 版本相同的 HK2 版本。

    【讨论】:

    • 我当然会使用HK2,但我的愿望是不要用手绑定所有的注射剂(起初我在看CDI - 没有必要这样做)。但它有效!非常感谢!我终于可以继续前进了。
    • 看看this。您可以在服务类上使用注释。当您使用居民生成器时,它会拾取注释。然后您可以创建ServiceLocator,并将其作为第三个参数传递给您的 GrizzlyHttpServerFactory.create 方法。
    • 哇,真的好用!需要提到的是,为此需要外部工具。但是有一个great maven plugin 存在。一切都按我的预期工作,无需手动绑定任何东西。你让我开心!
    【解决方案2】:

    是的,我认为上面的答案是正确的。一个很好的方法是将 Guice 连接到 HK2。我不是 100% 确定是否有必要在上面的代码中创建一个新的 TransportModule。事实上,Guice 在 ServletContext 中使用 Injector 的类名注册了它的注入器,因此可以从那里获取它:

            register(new ContainerLifecycleListener() {
            public void onStartup(Container container) {
                ServletContainer servletContainer = (ServletContainer)container;
                ServiceLocator serviceLocator = container.getApplicationHandler().getServiceLocator();
                GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
                GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
                Injector injector = (Injector) servletContainer.getServletContext().getAttribute(Injector.class.getName());
                guiceBridge.bridgeGuiceInjector(injector);
            }
            public void onReload(Container container) {
            }
            public void onShutdown(Container container) {
            }       
        });
    

    除此之外,如何以这种方式配置 REST 端点并非易事,所以我写了一篇关于 here 的详细博客。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-08
      • 2015-11-05
      相关资源
      最近更新 更多