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多数据源的更多相关文章

  1. springboot + mybatis + 多数据源

    此文已由作者赵计刚薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验 在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构: 简要原理: 1) ...

  2. spring-boot (四) springboot+mybatis多数据源最简解决方案

    学习文章来自:http://www.ityouknow.com/spring-boot.html 配置文件 pom包就不贴了比较简单该依赖的就依赖,主要是数据库这边的配置: mybatis.confi ...

  3. 第九章 springboot + mybatis + 多数据源 (AOP实现)

    在第八章 springboot + mybatis + 多数据源代码的基础上,做两点修改 1.ShopDao package com.xxx.firstboot.dao; import org.spr ...

  4. 【第九章】 springboot + mybatis + 多数据源 (AOP实现)

    在第八章 springboot + mybatis + 多数据源代码的基础上,做两点修改 1.ShopDao package com.xxx.firstboot.dao; import org.spr ...

  5. springboot mybatis 多数据源配置

    首先导入mybatis等包,这里就不多说. 下面是配置多数据源和mybatis,每个数据源对应一套mybatis模板 数据源1: package com.aaaaaaa.config.datasour ...

  6. 第八章 springboot + mybatis + 多数据源(转载)

    本篇博客转发自:http://www.cnblogs.com/java-zhao/p/5413845.html 在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构 ...

  7. 【第八章】 springboot + mybatis + 多数据源

    在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构: 简要原理: 1)DatabaseType列出所有的数据源的key---key 2)DatabaseConte ...

  8. 第八章 springboot + mybatis + 多数据源2(解决循环引用)

    解决了循环引用 1.application.properties #the first datasource jdbc.names:1,2 jdbc1.driverClassName = com.my ...

  9. spring boot(七):springboot+mybatis多数据源最简解决方案

    说起多数据源,一般都来解决那些问题呢,主从模式或者业务比较复杂需要连接不同的分库来支持业务.我们项目是后者的模式,网上找了很多,大都是根据jpa来做多数据源解决方案,要不就是老的spring多数据源解 ...

随机推荐

  1. JavaScript library of crypto standards. 看源码

    crypto-js - npm https://www.npmjs.com/package/crypto-js crypto-js/docs/QuickStartGuide.wiki <wiki ...

  2. 【题解】P3129高低卡(白金)High Card Low Card

    [题解][P3129 USACO15DEC]高低卡(白金)High Card Low Card (Platinum) 考虑贪心. 枚举在第几局改变规则,在改变规则之前,尽量出比它大的最小的牌,在改变规 ...

  3. python 函数中的递归、lambda 、map reduce 等详解

    举例说明 #例1: ###递归函数求和 from traitlets.traitlets import Instance def mysum(L): print(L) if not L: return ...

  4. cetons 怎么强制卸载 PHP

    查看php版本命令: #php -v 这个命令是删除不干净的 #yum remove php 因为使用这个命令以后再用 #php -v 还是会看到有版本信息的..... 必须强制删除 #rpm -qa ...

  5. 简单通俗解释内外网IP与端口映射

    IP:分为外网IP和内网IP 也就是我们说的外网IP属于实体IP 实体IP,它是独一无二的,在网络的世界里,每一部计算机的都有他的位置,一个 IP 就好似一个门牌!例如,你要去百度的网站的话,就要去『 ...

  6. Spring Boot2.0之 整合JDBC

    很入门的知识,大家了解下就OK maven配置文件pom: spring: datasource: url: jdbc:mysql://localhost:3306/test username: ro ...

  7. python- 常见算法 python内置模块

    1.冒泡排序 需求:请按照从小到大对列表 [13, 22, 6, 99, 11] 进行排序 原理:相邻两个值进行比较,将较大的值放在右侧,依次比较! li=[39,11,43,88,765,9]for ...

  8. hdu 1042 N!(大数)

    题意:求n!(0 ≤ N ≤ 10000) 思路:大数,用数组存储 1.首先要考虑数据N!的位数,因为最大是10000!,可以计算一下大概是5+9000*4+900*3+90*2+10*1=38865 ...

  9. 初识Spacy

    之所以想接触Spacy,是看到其自称为工业级的应用,所以想尝试下 windows下安装Spacy:     直接安装pip install spacy是会报错的     解决方法:     到 htt ...

  10. UOJ_14_【UER #1】DZY Loves Graph_并查集

    UOJ_14_[UER #1]DZY Loves Graph_并查集 题面:http://uoj.ac/problem/14 考虑只有前两个操作怎么做. 每次删除一定是从后往前删,并且被删的边如果不是 ...