使用Jersey 2.0,如何为每个请求注册一个可绑定的实例?

…如果实例需要手动构建,可能是第三方工厂类? 以前,(泽西岛1.x),你会做这样的事情:

public class MyInjectableProvider extends PerRequestTypeInjectableProvider { public MyInjectableProvider() { super(MyInjectable.class); } @Override public Injectable getInjectable(ComponentContext ic, Context context) { MyInjectable myInjectableInstance = //... return new Injectable() { @Override public MyInjectable getValue() { return myInjectableInstance; } }; } } 

匿名本地类能够访问要在某个范围内返回的实例。 当您不使用具有默认构造函数的类时,这非常有用,但它们需要基于每个请求构建。

Jersey 2.0切换到HK2作为dependency injection框架,但是,迁移页面( https://jersey.java.net/documentation/latest/migration.html )没有提供这种绑定的示例,并且HK2文档没有提供使用AbstractBinder的示例。

为了进一步阐述,我正在尝试向我的资源提供资源本地的,与容器无关的JPA EntityManager实例。 这些必须从单件工厂类中获取,并且应该只针对单个“工作单元”,这在我的情况下是一个请求。 我知道有解决方法(只是注入工厂,或绑定到threadlocal),但我发现以前的解决方案优雅,并希望尽可能重新创建它。

编辑:
在仔细研究了HK2 javadocs之后,我发现类似的东西可以实现如下:

 public class MyInjectableProvider extends AbstractBinder implements Factory { @Override protected void configure() { bindFactory(this).to(MyInjectable.class); } @Override public MyInjectable provide() { return getMyInjectable(); } @Override public void dispose(MyInjectable instance) {} } 

并注册它…

 public class MyResourceConfig extends ResourceConfig { public MyResourceConfig() { register(new MyInjectableProvider()); } } 

这“似乎有效”,但似乎有点不清楚。 例如,从不调用dispose()。 此外,此绑定似乎隐含地表现为RequestScoped。 将配置修改为bindFactory(this).to(MyInjectable.class).in(RequestScoped.class); 似乎并没有真正改变行为。 我错过了什么,或者这是预期的解决方案?

代替Factory.dispose(T) ,注册可注射的CloseableService可以完成你想要的大部分工作。 将需要一个CloseableFactory适配器。 CloseableService在退出请求范围时closes()所有已注册的资源。

有关具体示例,请参阅下面的ConnectionFactory

 import org.glassfish.hk2.api.Factory; import org.glassfish.jersey.server.CloseableService; import javax.inject.Inject; import javax.ws.rs.InternalServerErrorException; import java.sql.Connection; import java.sql.SQLException; import static com.google.common.base.Preconditions.checkNotNull; public class ConnectionFactory implements Factory { private final CloseableService closeableService; @Inject public ConnectionFactory(CloseableService closeableService) { this.closeableService = checkNotNull(closeableService); } public Connection provide() { final Connection connection; try { connection = acquireConnection(); } catch (SQLException e) { throw new InternalServerErrorException(e); } try { closeableService.add(new CloseableConnection(connection)); } catch (Throwable t) { closeQuietly(connection); throw runtime(t); } return connection; } public void dispose(Connection connection) { closeQuietly(connection); } private static RuntimeException runtime(Throwable t) { throw ConnectionFactory.unchecked(t); } private static  T unchecked(Throwable t) throws T { throw (T) t; } private static void closeQuietly(Connection connection) { try { connection.close(); } catch (SQLException ignore) {} } } 

下面是一个不太通用的CloseableFactory版本 – 一个CloseableConnection

 import java.io.Closeable; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; import static com.google.common.base.Preconditions.checkNotNull; public final class CloseableConnection implements Closeable { private final Connection connection; public CloseableConnection(Connection connection) { this.connection = checkNotNull(connection); } public void close() throws IOException { try { connection.close(); } catch (SQLException e) { throw new IOException(e); } } }