Refresh DataSource using Spring+dbcp

℡╲_俬逩灬. 提交于 2019-12-06 11:07:46

I don't think there is such a support in plain DBCP, mostly because database connection properties are very rarely changing during the lifetime of the application. Also you will have to consider transition time, when some connections served by the old data source are still opened while others are already served from the new (refreshed) one.

Decorator/proxy approach

I would suggest you to write custom implementation of DataSource leveraging Decorator/Proxy design pattern. Your implementation would simply call target data source (created by DBCP), most of the time doing nothing more. But when you call some sort of refresh() method, your decorator will close previously created data source and create new one with fresh configuration. Remember about multi-threading!

@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

}

The createDsManuallyUsingSomeExternalConfigurationSource() method might look like this:

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

This is a rough equivalent of Spring bean:

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

You can't just inject such a target bean into your proxy/decorator RefreshableDataSource as you want data source configuration to be dynamic/refreshable, while Spring only allows you to inject static properties. This means that it is your responsibility to create an instance of target BasicDataSource, but as you can see, it is nothing scary.

Actually, I have a second thought: Spring SpEL AFAIK allows you to call other beans' methods from XML configuration. But this is a very wide topic.

JNDI approach

Another approach might be to use JNDI to fetch DataSource and use hot-deployment (it works with JBoss and its *-ds.xml files.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!