如果我使用Jersey 1.12,并且我有多个资源类,并且它们都需要访问一些共享上下文,那么注入依赖项的最佳方法是什么,无论是在资源类的构造函数中还是在处理程序方法中?我是否需要使用外部DI库,或者Jersey内置了什么?
也许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 */ } }
和酒吧:
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 */ } }
解决方法
我最终使用了Google Guice,这是一个轻量级的DI框架,可以很好地与Jersey集成.这就是我必须做的事情:
首先,我在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>
我希望将DAO实现为具有接口的单例:
public interface MySingletonDao { // ... methods go here ... }
和具体的实施:
@Singleton public class ConcreteMySingletonDao implements MySingletonDao { // ... methods go here ... }
像这样装饰资源类:
@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 ... } }
创建了一个将执行绑定的类:
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); } }); } }
我使用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(); }
EmptyServlet来自Sunny Gleason的示例代码,作为答案给出:https://stackoverflow.com/a/3296467 – 我原来的
root.addServlet(new ServletHolder(new ServletContainer(new PackagesResourceConfig("com.example.resource"))),"/*");
而不是线
root.addServlet(EmptyServlet.class,"/*");
但是这导致Jersey尝试执行依赖注入而不是Guice,这会导致运行时错误.