最近新创建一个整合项目,用到的数据库连接池最终选择的c3p0连接池,一般来说,c3p0连接池有有种初始化,一种是配置文件形式,一种是纯代码形式。
那么问题就来了,比如项目中有些项目需要在运行中的过程中动态修改某些信息,比如链接地址,端口,密码什么的,最明显的就是使用jsch最为跳板机为ssh方式连接mysql服务器的时候,可能会在部署的过程中出现端口被占用这种常见问题。
这样子一般都有几种方法:
第一种:每次启动之前修改配置
第二种:使用纯代码实现连接信息
第三种:使用配置文件形式,在启动前读取配置文件修改,或者在运行中重新初始化
第四种:使用配置+修改内存中的字段。
通过动态调试可以发现,c3p0连接池在获取每次的实例的时候,会调用C3P0Config.getUnspecifiedUserProperties的方法,这个方法是获取默认的连接信息,然后拼接我们在Config中的配置信息,返回一个HashMap类型的连接信息HashMap。
再跟进代码的过程中会发现一句:out.putAll( MAIN.defaultConfig.props );
这句代码的意思就是把默认配置+自己的Config的配置信息返回回来作为连接的初始化信息,所以我们要动态修改MAIN.defaultConfig.props的值即可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public static Map getUnspecifiedUserProperties(String configName)
{
Map out = new HashMap();
out.putAll( MAIN.defaultConfig.props );
if (configName != null)
{
NamedScope named = (NamedScope) MAIN.configNamesToNamedScopes.get( configName );
if (named != null)
out.putAll( named.props );
else
logger.warning("named-config with name '" + configName + "' does not exist. Using default-config.");
}
return out;
}
NamedScope defaultConfig;
HashMap configNamesToNamedScopes;
实现代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/这个才行的
//C3P0Config.MAIN.configNamesToNamedScopes,这个就是读取配置文件的Map数据
try {
Field configNamesToNamedScopesField = C3P0Config.MAIN.getClass().getDeclaredField("configNamesToNamedScopes");
configNamesToNamedScopesField.setAccessible(true);
HashMap configNamesToNamedScopes = (HashMap) configNamesToNamedScopesField.get(C3P0Config.MAIN);
Object configNamesToNamedScope = configNamesToNamedScopes.get("jsch" + "_" + this.mysqlConnectionEnum.getName());//NamedScope
Field propsField = configNamesToNamedScope.getClass().getDeclaredField("props");
propsField.setAccessible(true);
HashMap props = (HashMap) propsField.get(configNamesToNamedScope);
String jdbcUrl = (String) props.get("jdbcUrl");
log.warn("修改之前的jdbcUrl:{}",jdbcUrl);
jdbcUrl = jdbcUrl.replace(String.valueOf(lport), String.valueOf(port));
props.put("jdbcUrl", jdbcUrl.replace(String.valueOf(lport), String.valueOf(port)));//覆盖c3p0的配置信息
log.warn("修改之前的jdbcUrl:{}",jdbcUrl);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
现在就可以修改在内存中的c3p0的信息了啦~又不需要对文件操作,也不用更新啥的,就可以轻松避免每次启动失败修改端口以及纯代码实现连接或者是自己读取修改配置文件,这样子不方便管理配置信息,毕竟别人已经实现了一套东西,我们只需要按需,然后看代码进行修改处理。或者可以使用动态代理处理,这里使用的是纯反射,简单明了~(也不简单了,被自己坑了一晚,,,还得加强源码阅读能力了)