java dependency-injection jersey jersey-2.0

java - Utilizando Jersey 2.0, ¿cómo se registra una instancia enlazable por solicitud?



dependency-injection jersey-2.0 (1)

En lugar de Factory<T>.dispose(T) , el registro con el Factory<T>.dispose(T) puede hacer la mayoría de lo que desea. Se requerirá un adaptador CloseableFactory . CloseableService closes() todos los recursos registrados al salir del alcance de la solicitud.

Para un ejemplo específico, vea la sección de ConnectionFactory continuación.

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 continuación se muestra una versión menos general de un CloseableFactory - un 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); } } }

... si la instancia necesita construirse manualmente, tal vez por una clase de fábrica de terceros? Anteriormente, (Jersey 1.x), harías algo como esto:

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

La clase local anónima puede acceder a una instancia para regresar dentro de algún alcance. Esto es útil cuando no está trabajando con clases que tienen constructores predeterminados, pero deben construirse para cada solicitud.

Jersey 2.0 cambió a HK2 como marco de inyección de dependencias, pero, por desgracia, la página de migración ( https://jersey.java.net/documentation/latest/migration.html ) no proporciona un ejemplo de este tipo de enlace, y La documentación HK2 no proporciona ejemplos utilizando un AbstractBinder.

Para elaborar un poco más, estoy tratando de proporcionar instancias JPA EntityManager de recursos locales e independientes del contenedor a mis recursos. Estos deben ser obtenidos de una clase de fábrica de singleton, y solo deben quedarse para una sola "unidad de trabajo", que es una solicitud en mi caso. Soy consciente de que existen soluciones alternativas (solo inyecte la fábrica o enlace a un threadlocal), pero la solución anterior me pareció elegante y me gustaría recrearla si es posible.

EDITAR:
Después de revisar un poco los javadocs HK2, descubrí que se puede lograr algo similar de la siguiente manera:

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

Y para registrarlo ...

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

Esto "parece funcionar", pero también parece poco claro. dispose () nunca se llama, por ejemplo. Además, este enlace parece comportarse implícitamente como RequestScoped. Modificación de la configuración a bindFactory(this).to(MyInjectable.class).in(RequestScoped.class); no parece realmente cambiar el comportamiento ¿Me estoy perdiendo algo, o es esta la solución deseada?