从canal-adapter文档我们可以知道,其实adapter本身是有从数据库读取配置的功能的,但是文档中只是简单的提了一句,本文就从代码入手,带大家看看adapter从数据库读取配置这部分的功能是如何实现以及应该如何去使用它。
主要介绍几个关键的位置,帮助大家理清思路
@PostConstruct
public void loadRemoteConfig() {
remoteConfigLoader = RemoteConfigLoaderFactory.getRemoteConfigLoader(env);
if (remoteConfigLoader != null) {
remoteConfigLoader.loadRemoteConfig();
remoteConfigLoader.loadRemoteAdapterConfigs();
remoteConfigLoader.startMonitor(); // 启动监听
}
}
以上就是adaper从数据库读取配置的所有内容。。。
惊不惊喜?作者现在真实越来越短了!
但是,事实就是如此,咳咳,为了证明我很长!给大家具体介绍一下!
public static RemoteConfigLoader getRemoteConfigLoader(Environment env) {
try {
String jdbcUrl = env.getProperty("canal.manager.jdbc.url");
if (!StringUtils.isEmpty(jdbcUrl)) {
// load remote config
String driverName = env.getProperty("canal.manager.jdbc.driverName");
String jdbcUsername = env.getProperty("canal.manager.jdbc.username");
String jdbcPassword = env.getProperty("canal.manager.jdbc.password");
return new DbRemoteConfigLoader(driverName, jdbcUrl, jdbcUsername, jdbcPassword);
}
// 可扩展其它远程配置加载器
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return null;
}
可以看出,getRemoteConfigLoader是从boostrap.yml里面去初始化了一个数据库链接,这个数据库连接干啥的?当然是存我们的adapter配置的了啦,我们继续往下看
@Override
public void loadRemoteConfig() {
try {
// 加载远程adapter配置
ConfigItem configItem = getRemoteAdapterConfig();
if (configItem != null) {
if (configItem.getModifiedTime() != remoteAdapterConfigHolder.getAdapterConfigTimestamp()) {
remoteAdapterConfigHolder.setAdapterConfigTimestamp(configItem.getModifiedTime());
overrideLocalCanalConfig(configItem.getContent());
logger.info("## Loaded remote adapter config: application.yml");
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
/**
* 获取远程application.yml配置
*
* @return 配置对象
*/
private ConfigItem getRemoteAdapterConfig() {
String sql = "select name, content, modified_time from canal_config where id=2";
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if (rs.next()) {
ConfigItem configItem = new ConfigItem();
configItem.setId(2L);
configItem.setName(rs.getString("name"));
configItem.setContent(rs.getString("content"));
configItem.setModifiedTime(rs.getTimestamp("modified_time").getTime());
return configItem;
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return null;
}
看着两个方法的名字其实就知道,他们是用来加载application和mapping同步表映射配置的
以loadRemoteConfig为例,注意这个sql
String sql = "select name, content, modified_time from canal_config where id=2";
select id, category, name, modified_time from canal_adapter_config
可以看出,application的配置是从canal_config表中获取的,配置id为2,所以只需把application的配置插入到canal_config表中,id为2,adapter就能从数据库中读取相应的配置了,loadRemoteAdapterConfigs做的操作与这里大致一致(canal_adapter_config表),大家可以自己去阅读一下代码,同时注意这段代码
if (configItem.getModifiedTime() != remoteAdapterConfigHolder.getAdapterConfigTimestamp()) {
remoteAdapterConfigHolder.setAdapterConfigTimestamp(configItem.getModifiedTime());
overrideLocalCanalConfig(configItem.getContent());
logger.info("## Loaded remote adapter config: application.yml");
}
这里对adapter的配置的时间做了判断,你猜这里是做什么的?
@Override
public void startMonitor() {
// 监听application.yml变化
executor.scheduleWithFixedDelay(() -> {
try {
loadRemoteConfig();
} catch (Throwable e) {
logger.error("scan remote application.yml failed", e);
}
}, 10, 3, TimeUnit.SECONDS);
// 监听adapter变化
executor.scheduleWithFixedDelay(() -> {
try {
loadRemoteAdapterConfigs();
} catch (Throwable e) {
logger.error("scan remote adapter configs failed", e);
}
}, 10, 3, TimeUnit.SECONDS);
}
没错,时间做判断,就是为了实现这里的数据监听,可以看到,这里会定时的去执行相关配置的load操作,当配置表中的modified_time与程序中记录的不同时,则去刷新相应的配置。
以上就是adapter通过数据库方式获取配置信息启动并持续监听配置变化的过程,那要如何使用呢?
如果我要启动多个adapter,使用不同的配置,是不是可以改造一下id=2这个让人非常在意的地方?
欢迎关注我的个人微信公众号,一个菜鸟程序猿的技术分享和奔溃日常