Когда использовать @Singleton на ресурсе Джерси - PullRequest
10 голосов
/ 01 мая 2010

У меня есть ресурс Джерси, который обращается к базе данных. В основном это открывает соединение с базой данных при инициализации ресурса. Выполняет запросы по методам ресурса.

Я заметил, что когда я не использую @Singleton, база данных открывается при каждом запросе. И мы знаем, что открытие соединения действительно дорого, верно?

Таким образом, мой вопрос заключается в том, должен ли я указывать, что ресурс должен быть одноэлементным, или действительно лучше сохранять его на уровне запроса, особенно когда ресурс подключается к базе данных?

Мой код ресурса выглядит так:

//Use @Singleton here or not?
@Path(/myservice/)
public class MyResource {

    private ResponseGenerator responser;
    private Log logger = LogFactory.getLog(MyResource.class);

    public MyResource() {
        responser = new ResponseGenerator();
    }

    @GET
    @Path("/clients")
    public String getClients() {

        logger.info("GETTING LIST OF CLIENTS");

        return responser.returnClients();
    }

    ...
    // some more methods
    ...

}

И я подключаюсь к базе данных, используя код, подобный следующему:

public class ResponseGenerator {
    private Connection conn;
    private PreparedStatement prepStmt;
    private ResultSet rs;

    public ResponseGenerator(){
        Class.forName("org.h2.Driver");
        conn = DriverManager.getConnection("jdbc:h2:testdb");
    }

    public String returnClients(){
        String result;
        try{
           prepStmt = conn.prepareStatement("SELECT * FROM hosts");

           rs = prepStmt.executeQuery();

           ...
           //do some processing here
           ...
        } catch (SQLException se){
            logger.warn("Some message");
        } finally {
            rs.close();
            prepStmt.close();
            // should I also close the connection here (in every method) if I stick to per request
            // and add getting of connection at the start of every method
            // conn.close();
        }

        return result
    }

    ...
    // some more methods
    ...

}

Некоторые комментарии по передовым методам для кода также будут полезны.

Ответы [ 2 ]

0 голосов
/ 18 сентября 2016

Вместо того, чтобы думать о том, чтобы сделать ресурс единичным, сосредоточьтесь больше на управлении внутренними объектами типа службы, такими как класс ResponseGenerator, как синглетами, которые, очевидно, не должны создаваться для каждого запроса.

Создание ресурсаСинглтон также является одним из способов управления ResponseGenerator как синглтоном, но это не единственный или обязательно лучший способ, см. Доступ к внешним объектам в классе ресурсов Джерси и Как подключиться ксоавтор ресурса Джерси? , чтобы узнать, как внедрить его в не-синглтон ресурсы.

Обратите внимание, что вашему классу ResponseGenerator потребуется работа, прежде чем он будет функционировать как синглтон, независимо от того, внедрен ли он взапросить ресурс или создать экземпляр в одноэлементном ресурсе.Это не потокобезопасно, и вы открываете одно соединение при запуске и повторно используете его в запросах, что не работает, вы должны использовать пул соединений, чтобы выполнить тяжелую работу по эффективному + безопасному повторному использованию соединений между запросами.

Некоторые комментарии по передовым методам для кода также будут полезны.

Вы получите лучшие ответы на http://codereview.stackexchange.com,, но:

  • ResponseGenerator - плохое имя для класса (почти все в веб-приложении является генератором ответов).

  • не использовать String в качестве возвращаемого типаваш сервис и объект, используйте правильно типизированные объекты (например, звучит так, как будто вы возвращаете java.util.List чего-либо).

  • Не глотайте свое исключение SQLException, поднимайте его, чтобы позволитьДжерси, чтобы сгенерировать код ответа серии 5xx в вашем ресурсе.

  • Использовать конечные переменные-члены.

  • Ваш объект журнала должен быть статическим.

0 голосов
/ 21 мая 2010

Лучшим вариантом для вас является использование фреймворка, такого как Spring with Jersey, который я описал в аналогичной записи . Единственное отличие состоит в том, что вместо внедрения служебного компонента вы вводите объединенный источник данных, и это можно легко настроить с помощью c3p0 .

Пример applicationContext.xml, обратите внимание, что «scope» установлен на prototype, что эквивалентно синглтону на языке Spring.

<bean id="pooledDataSource" scope="prototype" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="jdbcUrl" value="${jpa.url}" />
    <property name="user" value="${jpa.username}" />
    <property name="password" value="${jpa.password}" />
    <property name="initialPoolSize" value="1" />
    <property name="minPoolSize" value="1" />
    <property name="maxPoolSize" value="3" />
    <property name="idleConnectionTestPeriod" value="500" />
    <property name="acquireIncrement" value="1" />
    <property name="maxStatements" value="50" />
    <property name="numHelperThreads" value="1" />
</bean>

В вашем MyResource.java вы просто добавили бы следующее, и Spring вставил бы его соответствующим образом.

private DataSource pooledDataSource;
public void setPooledDataSource(DataSource pooledDataSource) {
    this.pooledDataSource = pooledDataSource;
}

Затем вы можете изменить свой ResponseGenerator для принятия источника данных и использовать его для запроса базы данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...