1.DBIdentifier
public class DBIdentifier {
private static ThreadLocal<String> projectCode = new ThreadLocal<String>();
public static String getProjectCode() {
return projectCode.get();
}
public static void setProjectCode(String code) {
projectCode.set(code);
}
}
2.DynamicDataSource
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.springframework.beans.factory.annotation.Autowired;
public class DynamicDataSource extends DataSource {
private static Logger log = LogManager.getLogger(DynamicDataSource.class);
@Autowired
private UserService userService;
@Override
public Connection getConnection(){
String projectCode = DBIdentifier.getProjectCode();
DataSource dds = DDSHolder.instance().getDDS(projectCode);
if (dds == null) {
try {
DataSource newDDS = initDDS(projectCode);
DDSHolder.instance().addDDS(projectCode, newDDS);
} catch (IllegalArgumentException | IllegalAccessException e) {
log.error("Init data source fail. projectCode:" + projectCode);
return null;
}
}
dds = DDSHolder.instance().getDDS(projectCode);
try {
return dds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
private DataSource initDDS(String projectCode) throws IllegalArgumentException, IllegalAccessException {
DataSource dds = new DataSource();
PoolProperties property = new PoolProperties();
Field[] pfields = PoolProperties.class.getDeclaredFields();
for (Field f : pfields) {
f.setAccessible(true);
Object value = f.get(this.getPoolProperties());
try
{
f.set(property, value);
}
catch (Exception e)
{
log.info("Set value fail. attr name:" + f.getName());
continue;
}
}
dds.setPoolProperties(property);
User user=userService.getUserListByCustomId(projectCode);
String url = "jdbc:mysql://"+user.getHeroIp()+":"+ user.getHeroPort()+"/"+
user.getHeroName()+"?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&autoReconnect=true";
dds.setUrl(url);
dds.setUsername(user.getHeroUserName());
dds.setPassword(user.getHeroUserPassword());
return dds;
}
}
3.DDSHolder
import org.apache.tomcat.jdbc.pool.DataSource;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
public class DDSHolder {
private Map<String, DDSTimer> ddsMap = new HashMap<>();
private static Timer clearIdleTask = new Timer();
static {
clearIdleTask.schedule(new ClearIdleTimerTask(), 5000, 60 * 1000);
};
private DDSHolder() {
}
public static DDSHolder instance() {
return DDSHolderBuilder.instance;
}
public synchronized void addDDS(String projectCode, DataSource dds) {
DDSTimer ddst = new DDSTimer(dds);
ddsMap.put(projectCode, ddst);
}
public synchronized DataSource getDDS(String projectCode) {
if (ddsMap.containsKey(projectCode)) {
DDSTimer ddst = ddsMap.get(projectCode);
ddst.refreshTime();
return ddst.getDds();
}
return null;
}
public synchronized void clearIdleDDS() {
Iterator<Map.Entry<String, DDSTimer>> iter = ddsMap.entrySet().iterator();
for (; iter.hasNext(); ) {
Map.Entry<String, DDSTimer> entry = iter.next();
if (entry.getValue().checkAndClose())
{
iter.remove();
}
}
}
private static class DDSHolderBuilder {
private static DDSHolder instance = new DDSHolder();
}
}
4.DDSTimer
import org.apache.tomcat.jdbc.pool.DataSource;
public class DDSTimer {
private static long idlePeriodTime = 10 * 60 * 1000;
private DataSource dds;
private long lastUseTime;
public DDSTimer(DataSource dds) {
this.dds = dds;
this.lastUseTime = System.currentTimeMillis();
}
public void refreshTime() {
lastUseTime = System.currentTimeMillis();
}
public boolean checkAndClose() {
if (System.currentTimeMillis() - lastUseTime > idlePeriodTime)
{
dds.close();
return true;
}
return false;
}
public DataSource getDds() {
return dds;
}
}
5.ClearIdleTimerTask
import java.util.TimerTask;
public class ClearIdleTimerTask extends TimerTask {
@Override
public void run() {
DDSHolder.instance().clearIdleDDS();
}
}
6.實現方法
DBIdentifier.setProjectCode(projectCode);