java Jersey 的依赖注入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10729482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dependency Injection with Jersey
提问by Shaggy Frog
If I am using Jersey 1.12, and I have multiple resource classes, and they all need to access some shared context, what's the best way to inject a dependency, whether it be in the constructor for the resource class, or into the handler method? Do I need to use an external DI library, or does Jersey have something built-in?
如果我使用 Jersey 1.12,并且我有多个资源类,并且它们都需要访问一些共享上下文,那么注入依赖项的最佳方法是什么,无论是在资源类的构造函数中,还是在处理程序方法中?我需要使用外部 DI 库,还是 Jersey 有内置的东西?
i.e. maybe the resource for Foos looks like this:
即 Foos 的资源可能是这样的:
package com.example.resource;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;
@Path("/some/api/path/foo")
public class FooResource
{
@GET
@Produces("text/html")
public String getFoo(@QueryParam("id") String id)
{
Foo foo = /* get a Foo from some shared context based on id */
/* Process foo into a String */
}
}
and for Bars:
对于酒吧:
package com.example.resource;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;
@Path("/some/api/path/bar")
public class BarResource
{
@GET
@Produces("text/html")
public String getBar(@QueryParam("id") String id)
{
Bar bar = /* get a Bar from some shared context based on id */
/* Process bar into a String */
}
}
回答by Shaggy Frog
I ended up using Google Guice, which is a lightweight DI framework that integrates well with Jersey. Here's what I had to do:
我最终使用了 Google Guice,它是一个轻量级的 DI 框架,可以很好地与 Jersey 集成。这是我必须做的:
First, I added dependencies in the pom.xml:
首先,我在 pom.xml 中添加了依赖项:
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-guice</artifactId>
<version>1.12</version>
<scope>compile</scope>
</dependency>
I wanted a DAO implemented as a singleton with an interface:
我想要一个 DAO 实现为带有接口的单例:
public interface MySingletonDao
{
// ... methods go here ...
}
and a concrete implementation:
和一个具体的实现:
@Singleton
public class ConcreteMySingletonDao implements MySingletonDao
{
// ... methods go here ...
}
Decorated the resource classes like so:
像这样装饰资源类:
@Path("/some/path")
@RequestScoped
public class MyResource
{
private final MySingletonDao mySingletonDao;
@Inject
public MyResource(MySingletonDao mySingletonDao)
{
this.mySingletonDao = mySingletonDao;
}
@POST
@Produces("application/json")
public String post() throws Exception
{
// ... implementation goes here ...
}
}
Created a class that will do the bindings:
创建了一个将执行绑定的类:
public class GuiceConfig extends GuiceServletContextListener
{
@Override
protected Injector getInjector()
{
return Guice.createInjector(new JerseyServletModule()
{
@Override
protected void configureServlets()
{
bind(MyResource.class);
bind(AnotherResource.class);
bind(MySingletonDao.class).to(ConcreteMySingletonDao.class);
serve("/*").with(GuiceContainer.class);
}
});
}
}
I used Jetty instead of Glassfish to actually act as the server. In my functional test, that looks something like:
我使用 Jetty 而不是 Glassfish 来实际充当服务器。在我的功能测试中,它看起来像:
private void startServer() throws Exception
{
this.server = new Server(8080);
ServletContextHandler root =
new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);
root.addEventListener(new GuiceConfig());
root.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
root.addServlet(EmptyServlet.class, "/*");
this.server.start();
}
The EmptyServlet
comes from Sunny Gleason's sample code given out as an answer at: https://stackoverflow.com/a/3296467-- I originally had
将EmptyServlet
来自于给出了一个答案阳光格里森的示例代码:https://stackoverflow.com/a/3296467-我本来
root.addServlet(new ServletHolder(new ServletContainer(new PackagesResourceConfig("com.example.resource"))), "/*");
instead of the line
而不是线
root.addServlet(EmptyServlet.class, "/*");
But that caused Jersey to try and perform the dependency injection instead of Guice, which caused runtime errors.
但这导致 Jersey 尝试执行依赖注入而不是 Guice,从而导致运行时错误。
回答by Pavel Bucek
you can use SingletonTypeInjectableProvider: http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html
您可以使用 SingletonTypeInjectableProvider:http: //jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html
sample:
样本:
ResourceConfig resourceConfig = new DefaultResourceConfig();
resourceConfig.getSingletons().add(
new SingletonTypeInjectableProvider<Context, SingletonType>(
SingletonType.class, new SingletonType()) {});{code}
or you can create SingletonTypeInjectableProvider descendant, annotate it with @Provider add it as a class. The you can inject provided instance wherever you need and where standard Jersey injection kicks in.
或者您可以创建 SingletonTypeInjectableProvider 后代,使用 @Provider 对其进行注释,将其添加为一个类。您可以在任何需要的地方以及标准 Jersey 注入开始的地方注入提供的实例。
回答by jeff
There is a jersey-spring project that supports Spring dependency injection. Replace your jersey ServletContainer with a SpringServlet, add a ContextLoaderListener to your web.xml and you can inject beans into your components. Here's a pretty decent walkthrough of the setup
有一个支持 Spring 依赖注入的 jersey-spring 项目。将您的 jersey ServletContainer 替换为 SpringServlet,将 ContextLoaderListener 添加到您的 web.xml,您就可以将 bean 注入到您的组件中。这是一个相当不错的设置演练
http://www.mkyong.com/webservices/jax-rs/jersey-spring-integration-example/
http://www.mkyong.com/webservices/jax-rs/jersey-spring-integration-example/
EDIT
编辑
Here's an idea that doesn't require adding any dependencies. Create your own ServletContextListener that adds your objects to the ServletContext. Then inject the ServletContext into your Resources
这是一个不需要添加任何依赖项的想法。创建您自己的 ServletContextListener,将您的对象添加到 ServletContext。然后将 ServletContext 注入到您的资源中
public class MyContextListener implements ServletContextListener
{
@Override
public void contextDestroyed(ServletContextEvent event)
{
}
@Override
public void contextInitialized(ServletContextEvent event)
{
ServletContext context = event.getServletContext();
context.setAttribute(Foo.class.getName(), new FooImpl());
}
}
Then in your Resource
然后在你的资源中
@Path("blah")
public class MyResource
{
private Foo foo;
public MyResource(@Context ServletContext context)
{
foo = (Foo) context.getAttribute(Foo.class.getName());
}
}
回答by nwallman
You do not have to use an external library unless you want to. It's well documented that getting CDI to work correctly with Jersey is currently a pain. However I can speak from experience that it can be done having done it myself. It's been awhile since I jumped through those hoops but I seem to recall we had to make our Resources Stateless EJB's to get it to work. There could have been other steps I took but I don't recall those now.
除非您愿意,否则您不必使用外部库。有据可查的是,目前让 CDI 与 Jersey 一起正常工作是一件很痛苦的事情。但是,我可以从经验中说,可以自己完成。自从我跳过这些障碍已经有一段时间了,但我似乎记得我们必须使我们的资源成为无状态 EJB 才能让它工作。我可能还采取了其他步骤,但我现在不记得这些步骤了。
When Jersey 2.0 comes out this should get a whole lot easier as they'll be switching over to using the Core CDI implementation instead of their own. See this bug for more info:
当 Jersey 2.0 出现时,这应该会变得更容易,因为他们将切换到使用 Core CDI 实现而不是他们自己的实现。有关更多信息,请参阅此错误: