Как правильно переопределить BasicDataSource для Spring и Hibernate - PullRequest
3 голосов
/ 20 декабря 2010

В настоящее время у меня есть следующий основной источник данных в Spring:

<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/test?relaxAutoCommit=true" />
    ...
</bean>

Теперь мне нужно предоставить пользовательский источник данных, основанный на серверной среде (не в конфигурации), для которого мне нужно вычислить поля driverClassName и url на основе некоторого условия.

Я попытался переопределить createDataSource() метод:

public class MyDataSource extends BasicDataSource {

    @Override
    protected synchronized DataSource createDataSource() throws SQLException {
        if(condition) {
            super.setDriverClassName("com.mysql.jdbc.Driver");
            super.setUrl("jdbc:mysql://localhost/test?relaxAutoCommit=true");
        } else {
            //...
        }
        return super.createDataSource();
    }
}

Что работает, но я заметил, что createDataSource() вызывается каждый раз, когда выполняется запрос (?), Поэтому я бы предпочел перенести тестирование условий в другое место.

Я попытался переопределить setDriverClassName() и setUrl(), который также работает и вызывается только один раз из того, что я могу сказать, но затем мне нужно предоставить некоторые значения в конфигурации Spring, чтобы вызвать эти установщики, поскольку они не вызываются в противном случае:

<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="whatever" />
    <property name="url" value="whatever" />
    ...
</bean>

, что может показаться странным.

Есть ли лучшие решения?

1 Ответ

4 голосов
/ 20 декабря 2010

Нет необходимости расширять BasicDataSource. Наследование является самой сильной формой сцепления, и его следует избегать, если только у вас нет реальной причины его использовать.

У вас есть два варианта:

  • Создание оболочки (используйте композицию вместо наследования)

    public class MyDataSource implements DataSource {
        private BasicDataSource target = new BasicDataSource();
        public MyDataSource() {
            if (condition) {
                target.setDriverClassName("com.mysql.jdbc.Driver");                
                target.setUrl("jdbc:mysql://localhost/test?relaxAutoCommit=true"); 
            } else { ... }
        }
        public Connection getConnection() {
            return target.getConnection();
        }
        ... etc ...
    }
    
  • Создание фабрики (поскольку вам нужно настроить только фазу создания объекта, вам не нужно контролировать весь срок его существования).

     public class MyDataSourceFactory {
        public DataSource createDataSource() {
            BasicDataSource target = new BasicDataSource();
            if (condition) {
                target.setDriverClassName("com.mysql.jdbc.Driver");                
                target.setUrl("jdbc:mysql://localhost/test?relaxAutoCommit=true"); 
            } else { ... }
            return target;
        }
    }
    

    .

    <bean id = "factory" class = "MyDataSourceFactory" />
    <bean id = "dbcpDataSource" 
         factory-bean = "factory" factory-method = "createDataSource">
         <property ... />
    </bean>
    

РЕДАКТИРОВАТЬ: Обратите внимание, что вы все еще можете настроить объект, полученный с завода, как обычный боб Spring.

Также, если ваше условие достаточно простое, вы можете вообще не писать свой собственный код, используя декларативные подходы, предоставляемые Spring, такие как Язык выражений Spring .

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