【问题标题】:Guice - Jersey - Servlet bindingGuice - Jersey - Servlet 绑定
【发布时间】:2013-09-29 02:43:38
【问题描述】:

我最近切换到两阶段注入,这在我的 servlet 绑定中产生了错误。我目前在两种错误模式之间切换,不确定哪个方向最好。

我遇到的第一个错误是:

com.sun.jersey.api.container.ContainerException:资源配置 实例不包含任何根资源类。

我的 servlet 模块如下所示:

public class MyServletModule extends JerseyServletModule {
    @Override
    protected void configureServlets() {
        bind(MyServlet.class).asEagerSingleton();

        serve("/*").with(GuiceContainer.class);
    }
}

我能够通过显式提供 com.sun.jersey.config.property.packages 参数来消除此错误。

public class MyServletModule extends JerseyServletModule {

    @Override
    protected void configureServlets() {
        bind(MyServlet.class).asEagerSingleton();

        Map<String,String> parameters = new HashMap<String, String>();
        parameters.put(PackagesResourceConfig.PROPERTY_PACKAGES, MyServlet.class.getPackage().getName());
        serve("/*").with(GuiceContainer.class, parameters);
    }
}

但是当我这样做时,Guice 会尝试一个 Just in Time 绑定,它不尊重我的 servlet 构造函数上的 @Inject。

com.google.inject.ConfigurationException:Guice 配置错误:

1) 无法为 MyServlet 创建绑定。已经配置好了 在一个或多个子注入器或私有模块上 绑定在 MyServletModule.configureServlets(MyServletModule.java:44) 如果是 在 PrivateModule 中,您是否忘记公开绑定?尽管 定位 MyServlet

1 处错误 com.google.inject.internal.InjectorImpl.getBinding(InjectorImpl.java:150)

我的 servlet 有一个 @Inject 构造函数,它的参数不能及时绑定。在调试到 InjectorImpl 之后,我相信这就是我使用 PROPERTY_PACKAGES 时失败的原因。

我只是不确定使用 PROPERTY_PACKAGES 是否正确,我需要修复一些绑定?或者,如果这是错误的方向,我需要以不同的方式修复原始 ResourceConfig 错误。

感谢您向正确方向提供帮助或推动。

【问题讨论】:

    标签: java servlets jersey guice


    【解决方案1】:

    通过单独绑定资源,我能够在不使用绑定参数(无需显式提供 com.sun.jersey.config.property.packages 参数)的情况下将 Jersey 资源绑定到 Guice

    public class BindJerseyResources extends ServletModule {
    
        @Override
        protected void configureServlets() {
            // excplictly bind GuiceContainer before binding Jersey resources
            // otherwise resource won't be available for GuiceContainer
            // when using two-phased injection
            bind(GuiceContainer.class);
    
            // bind Jersey resources
            PackagesResourceConfig resourceConfig = new PackagesResourceConfig("jersey.resources.package");
            for (Class<?> resource : resourceConfig.getClasses()) {
                bind(resource);
            }
    
            // Serve resources with Jerseys GuiceContainer
            serve("/*").with(GuiceContainer.class);
        }
    }
    

    资源如下

    @Path("/")
    @RequestScoped
    public class Resource {
    
        private Storage storage;
    
        @Inject
        public Resource(Storage storage) {
            this.storage = storage;
        }
    
        @GET
        @Path("get/{name}")
        @Produces(MediaType.TEXT_PLAIN)
        public String getGuid(@PathParam("name") String name) {
            return storage.get(name);
        }
    }
    

    也许这可以帮助您避免后一种有问题的绑定。


    更新了使用两阶段注射的答案。

    【讨论】:

    • 这似乎在他们的包中识别出我的 servlet,我得到一个信息级别日志,上面写着“INFO:找到根资源类:”但后来我仍然收到错误“com.sun.jersey.api .container.ContainerException:ResourceConfig 实例不包含任何根资源类。”
    • 奇怪,我在使用GuiceContainer 时没有任何此类例外。我从上面代码 sn-ps 所在的项目中提取了示例。也许这可以帮助您解决问题(如果问题是由某些版本的 Jersey 或 Guice 引起的)示例在 Github:github.com/reap/jetty-guice-jersey-example
    • 这是一个很好的例子,如果我将 InitializeGuiceModulesContextListener 中的代码转换为像这样使用两阶段注入,我可以轻松重现我的问题: return Guice.createInjector(new BindServicesModule()).createChildInjector(new BindJerseyResourcesModule ());显然,在这种情况下,仅出于演示目的而强制使用两相注入,但在我的情况下实际上需要它。
    • 谢谢,现在我也可以重现错误了。问题似乎是给予GuiceContainer 的注射器不包含泽西资源,在我看来,给予GuiceContainer 的注射器实际上是父注射器(由Guice.createInjector(new BindServicesModule()) 创建的注射器而不是childInjector ),因为以GuiceModule 结尾的注入器没有父级。
    • David B. 实际上在 (stackoverflow.com/questions/8454647/…) 中解决了这个问题,您需要在绑定资源之前显式绑定 GuiceContainer。我更新了example in github,它现在使用两阶段注入(更改在它自己的分支中)。我也更新了答案。
    【解决方案2】:

    Java部分

    import com.google.inject.Guice;
    import com.google.inject.Injector;
    import com.google.inject.Singleton;
    import com.google.inject.persist.jpa.JpaPersistModule;
    import com.google.inject.servlet.GuiceServletContextListener;
    import com.sun.jersey.guice.JerseyServletModule;
    import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
    import com.sun.jersey.spi.container.servlet.ServletContainer;
    import com.thjug.apipublic.Echo;
    
    public class ServletContextListener extends GuiceServletContextListener {
    
        @Override
        protected Injector getInjector() {
            final Injector injector = Guice.createInjector(new JerseyServletModule() {
                @Override
                protected void configureServlets() {
                    bind(Echo.class);
                    bind(ServletContainer.class).in(Singleton.class);
                    serve("/*").with(GuiceContainer.class);
                }
            }, new JpaPersistModule("dbUnit"), new LoggingModule());
    
            injector.getInstance(JPAInitializer.class);
            return injector;
        }
    }
    

    web.xml

        <distributable />
    
        <display-name>API</display-name>
    
        <filter>
                <filter-name>guiceFilter</filter-name>
                <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
        </filter>
        <filter-mapping>
                <filter-name>guiceFilter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <listener>
                <description>Guice Initiate</description>
                <listener-class>com.thjug.base.ServletContextListener</listener-class>
        </listener>
    

    以下是我关于如何使用 Guice 制作 REST 的主题演讲 http://www.slideshare.net/nuboat/lightweight-javaee

    【讨论】:

      【解决方案3】:

      这是一篇关于如何进行绑定的文章(包括完整的源代码): implementing-distributed-counter

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-20
        • 1970-01-01
        • 2013-06-21
        • 1970-01-01
        • 1970-01-01
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多