当持久化配置数据发生变化时,我编写了这个类来重新加载整个应用程序使用的DataSource。
如您所见,它由CDI管理,并作为一个Singleton公开,“配置更改”事件通过configurationReload(...)方法到达,但现在已经不相关了。
参考更新由ReentrantReadWriteLock保护,但我想知道是否需要它。
@Singleton
@ThreadSafe
class ReloadingDataSource implements DataSource {
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock readLock = readWriteLock.readLock();
private final Lock writeLock = readWriteLock.writeLock();
@GuardedBy("readWriteLock")
private DataSource delegateDataSource;
@Inject
ReloadingDataSource(@Nonnull final Configuration configuration) {
delegateDataSource = createDataSource(configuration);
}
private DataSource createDataSource(final Configuration configuration) {
... Create a ComboPooledDataSource using properties extracted from Configuration.
}
@Override
public Connection getConnection() throws SQLException {
readLock.lock();
try {
return delegateDataSource.getConnection();
} finally {
readLock.unlock();
}
}
...
private void configurationReload(
@Observes @Reload final ConfigurationChanged configurationChanged,
@Nonnull final Configuration configuration) {
final ConfigurationEvent event = configurationChanged.getConfigurationEvent();
if (event.getType() != AbstractFileConfiguration.EVENT_RELOAD && !event.isBeforeUpdate()) {
return;
}
writeLock.lock();
try {
destroyDelegateDataSource();
delegateDataSource = createDataSource(configuration);
} finally {
writeLock.unlock();
}
}
private void destroyDelegateDataSource() {
try {
DataSources.destroy(delegateDataSource);
} catch (final SQLException ignored) {
// Do nothing.
}
}
}如果我们忽略了创建一个新DataSource的成本,那么上面的策略是否会被一个AtomicReference<DataSource>所取代,如下所示?
它将导致更好的性能和更容易阅读的代码。
有没有更好的方法来处理这些我不知道的事情?
@Singleton
@ThreadSafe
class ReloadingDataSource implements DataSource {
private final AtomicReference<DataSource> delegateDataSource;
@Inject
ReloadingDataSource(@Nonnull final Configuration configuration) {
delegateDataSource = new AtomicReference<>(createDataSource(configuration));
}
private DataSource createDataSource(final Configuration configuration) {
... Create a ComboPooledDataSource using properties extracted from Configuration.
}
@Override
public Connection getConnection() throws SQLException {
return delegateDataSource.get().getConnection();
}
...
private void configurationReload(
@Observes @Reload final ConfigurationChanged configurationChanged,
@Nonnull final Configuration configuration) {
final ConfigurationEvent event = configurationChanged.getConfigurationEvent();
if (event.getType() != AbstractFileConfiguration.EVENT_RELOAD && !event.isBeforeUpdate()) {
return;
}
// Updated as per eckes tip. Is this what you meant?
final DataSource newDataSource = createDataSource(configuration);
while (true) {
final DataSource oldDataSource = delegateDataSource.get();
if (delegateDataSource.compareAndSet(oldDataSource, newDataSource)) {
destroyDelegateDataSource(oldDataSource);
break;
}
}
}
private void destroyDelegateDataSource(final DataSource oldDataSource) {
try {
DataSources.destroy(oldDataSource);
} catch (final SQLException ignored) {
// Do nothing.
}
}
}发布于 2018-10-08 20:08:12
如果需要以有序的方式处理更新,则仍然需要锁定重新加载方法。在这种情况下,您可以放弃AtomicReference逻辑,只需使用易失性:
public class RDS {
private volatile DataSource delegate;
public Connection getConnection() throws SQLException {
return delegate.getConnection();
}
private void reload(Configuration config) {
DataSource old = null;
synchronized(this) {
old = delegate;
delegate = createDataSource(config);
}
destroyDataSource(old);
}
}但是,您仍然可能会遇到其他问题,在关闭旧DataSource时,仍然会使用连接(在@eckes第一条注释中提到)。为了解决这个问题,您需要类似于带有获取/释放类型逻辑的连接池( connections ),该逻辑一旦释放了所有现有连接,就会关闭旧的委托。
https://stackoverflow.com/questions/52707808
复制相似问题