使用Jersey CDI自动关闭数据库连接?

时间:2015-11-25 10:42:51

标签: java jersey jersey-2.0

我想将一个实现AutoClosable的对象注入一个球衣资源,并在请求结束时由框架自动关闭。
基本上这是一个数据库连接提供程序,应在请求结束时关闭打开的连接 使用@inject注释时,对象未关闭 这有可能,怎么样?

2 个答案:

答案 0 :(得分:2)

您可以使用CloseableService

  

可以在请求范围内使用该服务,以便在请求超出范围时添加要关闭的Closeable实例,更具体地说,在处理请求并返回响应之后

您可以将此服务注入Factory,您可以在其中创建您的提供商。只需将提供商添加到CloseableService内的Factory,它就会在请求结束时关闭。

public class ConnectionProviderFactory implements Factory<ConnectionProvider> {

    @Inject
    private CloseableService closeableService;

    @Override
    public ConnectionProvider provider() {
        ConnectionProvider provider = new ConnectionProvider();
        closeableService.add(provider);
        return provider;
    }

    @Override
    public void dispose(ConnectionProvider provider) {
    }
}

然后只需在工具栏中注册工厂

bindFactory(ConnectionProviderFactory.class)
        .to(ConnectionProvider.class)
        .in(RequestScoped.class);

请注意,Factory类具有dispose方法。我不是百分之百肯定它的工作原理的细节,因为我有经验,有时它调用,有时它不是。我发现CloseableService更可靠。也许有一天我会去挖掘,试图为自己解决dispose方法的奥秘。

UPDATE

不完全确定您的做法有何不同,但以下是使用Jersey Test Framework进行的完整测试。像任何其他JUnit测试一样运行它。只有差异而不是AutoCloseable,我使用Closeable

import java.io.Closeable;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.CloseableService;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class InjectCloseableTest extends JerseyTest {

    public static final String CONNECTION_MSG = "Connection";

    public static class ConnectionProvider implements Closeable {
        private static final Logger LOGGER
                = Logger.getLogger(ConnectionProvider.class.getName());

        public String getConnection() {
            return CONNECTION_MSG;
        }

        @Override
        public void close() {
            LOGGER.info("---- Closing Connection ----");
        }  
    }

    @Path("connection")
    public static class ConnectionResource {

        @Inject
        ConnectionProvider connectionProvider;

        @GET
        public String get() {
            return connectionProvider.getConnection();
        }
    }

    public static class ConnectionProviderFactory implements Factory<ConnectionProvider> {

        @Inject
        CloseableService closeableService;

        @Override
        public ConnectionProvider provide() {
            ConnectionProvider provider = new ConnectionProvider();
            closeableService.add(provider);
            return provider;
        }

        @Override
        public void dispose(ConnectionProvider t) {} 
    }

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig(ConnectionResource.class)
                .register(new LoggingFilter(Logger.getAnonymousLogger(), true))
                .register(new AbstractBinder() {
                    @Override
                    protected void configure() {
                        bindFactory(ConnectionProviderFactory.class)
                                .to(ConnectionProvider.class)
                                .in(RequestScoped.class);
                    }
                });
    }

    @Test
    public void doit() {
        Response response = target("connection").request().get();
        assertEquals(200, response.getStatus());
        assertEquals(CONNECTION_MSG, response.readEntity(String.class));
        response.close();
    }
}

这是您运行它所需的唯一依赖项。

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey2.version}</version>
    <scope>test</scope>
</dependency>

答案 1 :(得分:0)

我认为您正在寻找@Disposes注释。

@Disposes注释标识disposer method的已处置参数,允许应用程序对producer methodproducer field返回的对象执行自定义清理。当范围结束时,将自动调用disposer方法。

我不知道您的数据库连接提供程序是什么样的,但是这个示例将为您提供有关如何使用@Disposes注释的一般概念:

public class Resources {

    @Produces
    @UserDatabase
    @RequestScoped
    @PersistenceContext
    private EntityManager em;

    public void close(@Disposes @UserDatabase EntityManager em) {
        em.close();
    }
}