使用Jersey 2.0,如何根据请求注册一个可绑定的实例? [英] Using Jersey 2.0, how do you register a bindable instance per request?
问题描述
...如果实例需要手动构建,也许是由第三方工厂类?以前,(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.
泽西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实例。这些必须从单身工厂班获得,只能坚持一个单一的工作单位,这是我的情况下的一个要求。我知道有解决方法(只是注入工厂,或绑定到一个threadlocal),但是我发现以前的解决方案是优雅的,如果可能,我们想重新创建它。
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>注意注入
CloseableService
可能会做大部分你想要的。将需要一个 CloseableFactory
适配器。 CloseableService
closing()
退出请求范围后的所有注册资源。
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
- a 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,如何根据请求注册一个可绑定的实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!