数据源的初始化
在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。这和我们要求找到一个数据源来抽象所有数据源,按照程序需要访问十分契合。
因为是一个抽象类,需要实现下面方法
@Override
protected Object determineCurrentLookupKey() {
return MultiDataSourcesSwitcher.getDataSourceType();
}
由使用者引入我们的配置文件,从而产生MultiDataSources这个类的bean。
public MultiDataSources() {
try {
initializeDataSources();
} catch (Exception e) {
throw new IllegalStateException("datasource initialize error..", e);
}
}
private void initializeDataSources() throws SQLException, IllegalAccessException {
for (String dbtype : dataSourceNames) {//dataSourceNames是本工程所有需要支持的数据源
DruidDataSource dataSource = this.dataSourceAssembler(dbtype);
dataSources.put(dbtype, dataSource);
targetDataSources.put(dbtype, dataSource);
}
defaultDBType = dataSourceList.getProperty("DefaultDataSource", null);
this.setDefaultTargetDataSource(targetDataSources.get(defaultDBType));
this.setTargetDataSources(targetDataSources);
}
private DruidDataSource dataSourceAssembler(String dbtype) throws IllegalAccessException, SQLException {
DruidDataSource dataSource = new DruidDataSource();
String namespace = config.getProperty(dbtype, null);
namespaceDataSource.put(namespace, dbtype);
Config ds = ConfigService.getConfig(namespace);
//处理用户名密码信息
dataSource.setFilters("com.umetrip.dal.druid.DataSourceConfigFilter");
// 处理了slowsqlmillis设置,首次设置时使用
ArrayList<Filter> statFilters = new ArrayList<>();
statFilters.add(getDruidStatFilterProxy(ds));
dataSource.setProxyFilters(statFilters);
Properties connectProperties = new Properties();
connectProperties.setProperty("config.decrypt", "true");
connectProperties.setProperty("dbtype", dbtype);
connectProperties.setProperty("config.name", configPassword.getProperty(dbtype, null));
dataSource.setConnectProperties(connectProperties);
for(String propertyName : ds.getPropertyNames()) {
if("username".equals(propertyName) || "password".equals(propertyName) || "slowsqlmillis".equals(propertyName)) continue;
dataSourceAssemblerHelper(dataSource, propertyName, ds.getProperty(propertyName, null));
}
//注册动态监听配置变化的Listener
ds.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
updateDataSource(changeEvent);
}
});
return dataSource;
}
//根据设置注入属性
private void dataSourceAssemblerHelper(DruidDataSource dataSource, String propertyName, String propertyVal) {
try {
//处理slowsqlmillis属性reload逻辑。方法是把上次注册的filter取出来删掉,重新建立新设置的filter载入
if (propertyName.equalsIgnoreCase("slowsqlmillis")) {
try {
List<Filter> proxyFilters = dataSource.getProxyFilters();
List<Filter> newFilters = new ArrayList<>();
for (Filter f : proxyFilters) {
if (AopUtils.isAopProxy(f)) {
StatFilter statFilter = new StatFilter();
statFilter.setSlowSqlMillis(Long.valueOf(propertyVal));
AspectJProxyFactory factory = new AspectJProxyFactory(statFilter);
factory.addAspect(UmeCatStatFilterAspect.class);
newFilters.add((Filter)factory.getProxy());
} else {
newFilters.add(f);
}
}
dataSource.clearFilters();
dataSource.setProxyFilters(newFilters);
return;
} catch (Exception e) {
e.printStackTrace();
}
return;
}
if("username".equals(propertyName) || "password".equals(propertyName)) {
return;
}
Field field = dataSource.getClass().getSuperclass().getDeclaredField(propertyName);
field.setAccessible(true);
switch (TypeName.valueOf(field.getType().getSimpleName().toUpperCase())) {
case INT:
case INTEGER:
field.set(dataSource, Integer.valueOf(propertyVal));
break;
case LONG:
field.set(dataSource, Long.valueOf(propertyVal));
break;
case BOOLEAN:
field.set(dataSource, Boolean.valueOf(propertyVal));
break;
case STRING:
field.set(dataSource, propertyVal);
break;
}
} catch (NoSuchFieldException | IllegalAccessException e) {
}
}
//更新设置
private void updateDataSource(ConfigChangeEvent changeEvent) {
DruidDataSource updateDS = (DruidDataSource)dataSources.get(namespaceDataSource.get(changeEvent.getNamespace()));
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
dataSourceAssemblerHelper(updateDS, change.getPropertyName(), change.getNewValue());
}
}