Zookeeper发布订阅之SpringBoot+Mybatis多数据源
1.前言
数据发布/订阅系统,即所谓的配置中心,顾名思义就是发布者将数据发布到Zookeeper的一个或一系列节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中管理和数据的动态更新。
发布订阅一般有两种模式,分别是推(Push)和拉(Pull)模式。在推拉模式中,服务端主动将数据更新发送给所有订阅的客户端;而拉模式则是客户端主动发起请求来获取最新数据。Zookeeper采取推和拉相结合的方式:客户端会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据。
“配置管理”的实际案例来展示Zookeeper在"数据发布/订阅"场景下的使用方式。
2.案例
将敏感的配置信息存放与Zookeeper中。启动项目时,自动从Zookeeper中获取。
Maven坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
自动从Zookeeper中获取”配置信息“,并放入Enviroment中
配置ApplicationContextInitializer,项目在启动先调用该类,进行加载环境变量到Enviroment中去(这里采用在classpath路径下新建META-INF/spring.factories文件方式,其它两种方式为:
1.使用SpringApplication 对象,调用 addInitializers()
2.在配置文件中配置 context.initializer.classes =xx)
spring.factories文件
# Initializers
org.springframework.context.ApplicationContextInitializer=\
com.example.zkconfig.config.GlobalConfigInit
GlobalConfigIn类进行一系列配置文件加载及Zk连接,我用的Curator框架 我的application.properties此刻内容
server.port=8076
#zk 配置信息
com.unconfig.info=/config/zk-config
application-dev 则对应具体连接机器
#zk
com.zookeeper.url=zk://192.168.159.129:2181
从zk取配置信息放入spring环境
@Slf4j
public class GlobalConfigInit implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
String zkUri = environment.getProperty("com.zookeeper.url");
if (null == zkUri) {
log.warn("could not find zk uri,unconf not configured..");
} else {
ZookeeperUtils zookeeperUtils = new ZookeeperUtils();
zookeeperUtils.setZkUri(zkUri);
String unconf = environment.getProperty("com.unconfig.info");
if (null != unconf) {
log.info("config uniconf .. {}", unconf);
ZkPropertySource propertySource = new ZkPropertySource("default", zookeeperUtils.getEnv(unconf));
environment.getPropertySources().addLast(propertySource);
} else {
log.warn("unconf not configured..");
}
}
} public String getEnv(Environment environment) {
String zkUrl = environment.getProperty("com.zookeeper.url");
if (null != zkUrl && !zkUrl.isEmpty()) {
return zkUrl;
} else {
String unConfig = environment.getProperty("com.unconfig.info");
if (unConfig != null && !unConfig.isEmpty()) {
ZookeeperURI parse = ZookeeperURI.parse(unConfig);
String inferZkUrl = "zk://" + parse.getServers();
System.setProperty("com.zookeeper.url", inferZkUrl);
log.info("inferred zk uri from unconf zk {}", inferZkUrl);
return inferZkUrl;
} else {
return null;
}
}
}
}
这里不再多说,接下来配置数据源。
@Configuration
@MapperScan(basePackages = {"com.example.zkconfig.dao.write"}, sqlSessionFactoryRef = "writeSqlSessionFactory")
public class WriteDataSourceConfig { @Value("${write.datasource.mappers}")
private String location; @Bean(name = "writeDataSource")
@ConfigurationProperties(prefix = "write.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
} @Bean(name = "writeSqlSessionFactory")
public SqlSessionFactory writeSqlSessionFactory(@Qualifier("writeDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources(location));
return sqlSessionFactoryBean.getObject();
} @Bean(name = "writeTransactionManager")
public DataSourceTransactionManager writeTransactionManager(@Qualifier("writeDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
而我实际在zookeeper节点配置的数据

测试走一波,启动成功。
Zookeeper发布订阅之SpringBoot+Mybatis多数据源的更多相关文章
- springboot + mybatis + 多数据源
此文已由作者赵计刚薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验 在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构: 简要原理: 1) ...
- spring-boot (四) springboot+mybatis多数据源最简解决方案
学习文章来自:http://www.ityouknow.com/spring-boot.html 配置文件 pom包就不贴了比较简单该依赖的就依赖,主要是数据库这边的配置: mybatis.confi ...
- 第九章 springboot + mybatis + 多数据源 (AOP实现)
在第八章 springboot + mybatis + 多数据源代码的基础上,做两点修改 1.ShopDao package com.xxx.firstboot.dao; import org.spr ...
- 【第九章】 springboot + mybatis + 多数据源 (AOP实现)
在第八章 springboot + mybatis + 多数据源代码的基础上,做两点修改 1.ShopDao package com.xxx.firstboot.dao; import org.spr ...
- springboot mybatis 多数据源配置
首先导入mybatis等包,这里就不多说. 下面是配置多数据源和mybatis,每个数据源对应一套mybatis模板 数据源1: package com.aaaaaaa.config.datasour ...
- 第八章 springboot + mybatis + 多数据源(转载)
本篇博客转发自:http://www.cnblogs.com/java-zhao/p/5413845.html 在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构 ...
- 【第八章】 springboot + mybatis + 多数据源
在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构: 简要原理: 1)DatabaseType列出所有的数据源的key---key 2)DatabaseConte ...
- 第八章 springboot + mybatis + 多数据源2(解决循环引用)
解决了循环引用 1.application.properties #the first datasource jdbc.names:1,2 jdbc1.driverClassName = com.my ...
- spring boot(七):springboot+mybatis多数据源最简解决方案
说起多数据源,一般都来解决那些问题呢,主从模式或者业务比较复杂需要连接不同的分库来支持业务.我们项目是后者的模式,网上找了很多,大都是根据jpa来做多数据源解决方案,要不就是老的spring多数据源解 ...
随机推荐
- cocos2d-js添加百通广告(通过jsb反射机制)
1.导入jar包,包括so文件 2.配置AndroidManifest.xml文件,添加: <!-- BDAPPUNIONSDK start --> <activity androi ...
- Struts2常见面试点
01. 三层和MVC的区别 http://blog.csdn.net/csh624366188/article/details/7183872 http://www.cnblogs.com/zdxs ...
- JavaScript 如何创建search字段
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- fastjson(转)
博客地址 :http://blog.csdn.NET/shulianghan/article/details/41011605 fastjson 源码地址 : -- GitHub : https:// ...
- 使用 eslint 和 editorconfig 规范代码
项目中使用eslint 为什么使用eslint : 为了保持代码风格的统一 在做vue项目的时候, 基本上都会使用 vue-cli 脚手架去创建一个vue 项目,里面可以选择使用eslint 代码检测 ...
- Swift 烧脑体操(四) - map 和 flatMap
前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困 ...
- Java对象 的创建与构造方法
一.创建对象的四种方法: a. new语句: b. 利用反射,调用描述类的Class对象的newInstance()实例方法: c. 调用对象的clone(): d. 反序列化: 其中new 和 ne ...
- 解决/usr/bin/ld: cannot find -lmysqlclient错误
类似/usr/bin/ld: cannot find -xxxx的错误有很多, 首先我们可以最简单的判断一下: 这类情况一般是由于缺乏某某库文件, 又或者可能是由于已存在的库问题版本不对造成的 一般都 ...
- Matlab图像处理(03)-基本概念
概念定义 动态范围:灰度跨跃的值域称为动态范围.上限取决于饱和度,下限取决于噪声. 对比度:一幅图像中最高和最低灰度级间的灰度差. 空间分辨率:图像中可辨别的最小细节的度量.常用度量每单位距离线对数和 ...
- <tx:advice/> 有关的设置
将描述通过 <tx:advice/> 标签来指定不同的事务性设置.默认的 <tx:advice/> 设置如下: 事务传播设置是 REQUIRED 隔离级别是 DEFAULT 事 ...