Using Jersey 2.0, how do you register a bindable instance per request?(使用 Jersey 2.0,如何为每个请求注册一个可绑定实例?)
问题描述
...如果需要手动构建实例,也许是由第 3 方工厂类?以前,(Jersey 1.x),你会做这样的事情:
...if the instance needs to be constructed manually, perhaps by a 3rd party factory class? Previously, (Jersey 1.x), you would do something like this:
public class MyInjectableProvider extends PerRequestTypeInjectableProvider<Context, MyInjectable> {
public MyInjectableProvider() {
super(MyInjectable.class);
}
@Override
public Injectable<MyInjectable> getInjectable(ComponentContext ic, Context context) {
MyInjectable myInjectableInstance = //...
return new Injectable<MyInjectable>() {
@Override
public MyInjectable getValue() {
return myInjectableInstance;
}
};
}
}
匿名本地类能够访问一个实例以在某个范围内返回.当您不使用具有默认构造函数的类时,这很有用,但它们需要根据每个请求进行构造.
The anonymous local class is able to access an instance to return within some scope. This is useful when you're not working with classes that have default constructors, but they need to be constructed on a per-request basis.
Jersey 2.0 切换到 HK2 作为依赖注入框架,可惜迁移页面(https://jersey.java.net/documentation/latest/migration.html) 没有提供这种绑定的示例,HK2 文档也没有提供使用 AbstractBinder 的示例.
Jersey 2.0 switched over to HK2 as a dependency injection framework, but alas, the migration page (https://jersey.java.net/documentation/latest/migration.html) doesn't provide an example of this kind of binding, and the HK2 documentation doesn't provide examples using an AbstractBinder.
为了详细说明,我试图为我的资源提供资源本地、容器无关的 JPA EntityManager 实例.这些必须从单例工厂类中获取,并且应该只保留一个工作单元",这在我的情况下是一个请求.我知道有一些解决方法(只需注入工厂,或绑定到线程本地),但我发现以前的解决方案很优雅,如果可能的话想重新创建它.
To elaborate just a bit more, I'm trying to provide resource-local, container-agnostic JPA EntityManager instances to my resources. These have to be fetched from a singleton factory class, and should only stick around for a single "unit of work," which is a request in my case. I'm aware there are workarounds (Just inject the factory, or bind to a threadlocal), but I found the previous solution elegant and would like to recreate it if possible.
在深入研究了 HK2 javadocs 之后,我发现可以实现类似的功能,如下所示:
After digging through the HK2 javadocs for a bit, I've discovered that something similar can be achieved as follows:
public class MyInjectableProvider extends AbstractBinder
implements Factory<MyInjectable> {
@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); 似乎并没有真正改变行为.我是否遗漏了什么,或者这是预期的解决方案?
This "seems to work," but it also seems a bit unclear. dispose() is never called, for example. Also, this binding seems to implicitly behave as RequestScoped. Modifying the configuration to bindFactory(this).to(MyInjectable.class).in(RequestScoped.class); doesn't appear to actually change the behavior. Am I missing something, or is this the intended solution?
推荐答案
代替 Factory<T>.dispose(T),注册可注入的 CloseableService 可能做大部分你想做的事.CloseableFactory 适配器将是必需的.CloseableService closes() 退出请求范围时所有注册的资源.
In place of Factory<T>.dispose(T), registering with the injectable CloseableService may do most of what you want. A CloseableFactory adapter will be required. CloseableService closes() all registered resources upon exiting the request scope.
具体示例请参见下面的ConnectionFactory.
For a specific example, see the ConnectionFactory below.
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<Connection> {
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.<RuntimeException>unchecked(t);
}
private static <T extends Throwable> T unchecked(Throwable t) throws T {
throw (T) t;
}
private static void closeQuietly(Connection connection) {
try {
connection.close();
} catch (SQLException ignore) {}
}
}
下面是一个不太通用的 CloseableFactory - CloseableConnection.
Below is a less general version of a CloseableFactory - a 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);
}
}
}
这篇关于使用 Jersey 2.0,如何为每个请求注册一个可绑定实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用 Jersey 2.0,如何为每个请求注册一个可绑定实例?
- Eclipse 插件更新错误日志在哪里? 2022-01-01
- C++ 和 Java 进程之间的共享内存 2022-01-01
- 如何使用WebFilter实现授权头检查 2022-01-01
- 将log4j 1.2配置转换为log4j 2配置 2022-01-01
- value & 是什么意思?0xff 在 Java 中做什么? 2022-01-01
- Safepoint+stats 日志,输出 JDK12 中没有 vmop 操作 2022-01-01
- Jersey REST 客户端:发布多部分数据 2022-01-01
- Java包名称中单词分隔符的约定是什么? 2022-01-01
- 从 finally 块返回时 Java 的奇怪行为 2022-01-01
- Spring Boot连接到使用仲裁器运行的MongoDB副本集 2022-01-01
