Обновите DataSource используя Spring + dbcp - PullRequest
2 голосов
/ 15 февраля 2011

Я использую Spring с DBCP, и мне нужно обновить источник данных при изменении конфигурации рабочей среды без перезапуска всех приложений.

Если я делаю это без использования DBCP, я запускаю это обновление, закрывая текущий открытый источник данных, который используется, и запускаю новый экземпляр DataSource.

Используя DBCP + Spring, я не могу этого сделать.

Кто-нибудь знает, возможно ли это?

1 Ответ

8 голосов
/ 15 февраля 2011

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

Подход Decorator / proxy

Я бы посоветовал вам написать собственную реализацию DataSource , использующую шаблон проектирования Decorator / Proxy.Ваша реализация просто вызовет целевой источник данных (созданный DBCP), большую часть времени ничего не делая.Но когда вы вызываете какой-то метод refresh(), ваш декоратор закроет ранее созданный источник данных и создаст новый с новой конфигурацией.Помните о многопоточности!

@Service
public class RefreshableDataSource implements DataSource {

    private AtomicReference<DataSource> target = new AtomicReference<DataSource>();

    @PostConstruct
    public void refresh() {
        target.set(createDsManuallyUsingSomeExternalConfigurationSource());
    }

    @Override
    public Connection getConnection() throws SQLException {
        return target.get().getConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return target.get().getConnection(username, password);
    }

    //Rest of DataSource methods

}

Метод createDsManuallyUsingSomeExternalConfigurationSource() может выглядеть следующим образом:

private DataSource createDsManuallyUsingSomeExternalConfigurationSource() {
    DataSource ds = new org.apache.commons.dbcp.BasicDataSource();
    ds.setDriverClassName("org.h2.Driver");
    ds.setUrl(/*New database URL*/);
    ds.setUsername(/*New username*/);
    ds.setPassword(/*New password*/);
    return ds;
}

Это грубый эквивалент bean-компонента Spring:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:mem:" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

Вы не можете просто внедрить такой целевой бин в прокси / декоратор RefreshableDataSource, так как вы хотите, чтобы конфигурация источника данных была динамической / обновляемой, в то время как Spring позволяет вводить только статические свойства.Это означает, что вы несете ответственность за создание экземпляра цели BasicDataSource, но, как видите, в этом нет ничего страшного.

На самом деле у меня есть вторая мысль: Spring SpEL AFAIK позволяет вам вызывать методы других компонентов из конфигурации XML.Но это очень широкая тема.

Подход JNDI

Другой подход может заключаться в использовании JNDI для извлечения DataSource и использования горячего развертывания (он работает с JBoss и его *-ds.xml файлами.

...