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

...如果实例需要手动构建,也许是由第三方工厂类构建?以前,(泽西岛 1.x),您会执行如下操作:

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;
            }
        };
    }
}

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

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

为了进一步详细说明,我正在尝试为我的资源提供资源本地,容器不可知的JPA EntityManager实例。这些必须从单例工厂类中获取,并且应该只停留在单个“工作单元”中,这在我的情况下是一个请求。我知道有解决方法(只需注入工厂,或绑定到线程局部),但我发现以前的解决方案很优雅,并希望尽可能重新创建它。

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

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);


答案 1

代替 ,使用注射器注册可以完成您想要的大部分操作。将需要适配器。 退出请求范围时的所有已注册资源。Factory<T>.dispose(T)CloseableServiceCloseableFactoryCloseableServicecloses()

有关具体示例,请参阅以下内容。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<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) {}
    }
}

下面是 a 的不太通用的版本 - a 。CloseableFactoryCloseableConnection

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);
        }
    }
}

答案 2

推荐