cn.bridgeli.masterslavedbselector.MasterSlaveSelectorByPoll Maven / Gradle / Ivy
package cn.bridgeli.masterslavedbselector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 数据库选择器
*/
public class MasterSlaveSelectorByPoll implements MasterSlaveSelector {
private static final Logger logger = LoggerFactory.getLogger(MasterSlaveSelectorByPoll.class);
public static final ThreadLocal holder = new ThreadLocal();
private List masters;
private List slaves;
private AtomicInteger selectedMasterIndex = new AtomicInteger(0);
private AtomicInteger selectedSlavesIndex = new AtomicInteger(0);
private List badMasters = Collections.synchronizedList(new ArrayList());
private List badSlaves = Collections.synchronizedList(new ArrayList());
private DataSource defaultDataSource;
@Override
public DataSource get() {
DataSource ds = holder.get();
return ds == null ? defaultDataSource : ds;
}
@Override
public void master() {
logger.debug("change master!");
if (!masters.contains(holder.get())) {
holder.set(getNext(selectedMasterIndex, masters));
}
}
/**
* 获取下个目标
*/
private DataSource getNext(AtomicInteger selectedIndex, List sources) {
if (sources.isEmpty()) {
throw new RuntimeException("No datasource available.");
}
selectedIndex.weakCompareAndSet(sources.size(), 0);
return sources.get(selectedIndex.getAndIncrement() % sources.size());
}
@Override
public void slave() {
logger.debug("change slave!");
if (holder.get() == null) {
holder.set(getNext(selectedSlavesIndex, slaves));
}
}
@Override
public void monitor() {
checkRestore(badMasters, masters);
checkRestore(badSlaves, slaves);
checkBadDataSource(masters, badMasters);
checkBadDataSource(slaves, badSlaves);
}
/**
* 检查异常的数据源是否恢复了
*/
private void checkBadDataSource(List normalDataSources,
List badDataSources) {
for (DataSource ds : normalDataSources) {
try {
ds.getConnection();
ds.getConnection().close();
} catch (Exception e) {
badDataSources.add(ds);
logger.error("Check new database error! database:" + ds, e.toString());
}
}
}
/**
* 检查恢复的数据库
*/
private void checkRestore(List badDataSources, List normalDataSources) {
for (DataSource ds : badDataSources) {
try {
ds.getConnection();
ds.getConnection().close();
normalDataSources.add(ds);
} catch (SQLException e) {
logger.error("Continue database error! database:" + ds, e.toString());
}
}
}
/**
* Setter method for property masters.
*
* @param masters value to be assigned to property masters
*/
public void setMasters(List masters) {
this.masters = Collections.synchronizedList(masters);
}
/**
* Setter method for property slaves.
*
* @param slaves value to be assigned to property slaves
*/
public void setSlaves(List slaves) {
this.slaves = Collections.synchronizedList(slaves);
}
/**
* Setter method for property defaultDataSource.
*
* @param defaultDataSource value to be assigned to property defaultDataSource
*/
public void setDefaultDataSource(DataSource defaultDataSource) {
this.defaultDataSource = defaultDataSource;
}
}