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. sql server charindex函数和patindex函数详解(转)

    charindex和patindex函数常常用来在一段字符中搜索字符或字符串.假如被搜索的字符中包含有要搜索的字符,那么这两个函数返回一个非零的整数,这个整数是要搜索的字符在被搜索的字符中的开始位数. ...

  2. TVirtualStringTree的Minimal例子学习

    预步骤第一步,定义数据结构type PMyRec = ^TMyRec; TMyRec = record Caption: WideString; end;预步骤第二步,规定取得节点数据时候的大小pro ...

  3. ABAP 设置单元格颜色

    http://blog.163.com/ronanchen@126/blog/static/172254750201161811040488/ http://blog.csdn.net/lhx20/a ...

  4. 使用了Tomcat JDBC连接池不能重连的问题

    在项目中用到了tomcat 的jdbc连接池,发现一个问题是,当数据库重启时,服务没有重新的去连接数据库,需要将部署的项目重新启动才能连接到数据库.经过测试对配置做一下修改: 在配置dataSourc ...

  5. Django的基础操作总结

    1:准备开始 建立一个新的project: django-admin.py startproject XXXXXX(名称) 建立一个新的App:python manage.py startapp XX ...

  6. 多线程(三) iOS中的锁

    锁的类别:互斥锁,递归锁,条件锁,自旋锁等 锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等 下面说一下常用的 ...

  7. 简单学习github代码托管

    之前尝试使用阿里云code做代码托管 egret+git+阿里云code搭建团队开发 ,现在来学习一下使用 Github做代码托管服务. 总体上看使用的步骤差不多,都需要使用GIT客户端来进行相关的操 ...

  8. Linux线程的几种结束方式

    Linux创建线程使用 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) ...

  9. linux内核 RCU机制详解【转】

    本文转载自:https://blog.csdn.net/xabc3000/article/details/15335131 简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前 ...

  10. java语言中Object对象的hashCode()取值的底层算法是怎样实现的

    Java语言中,Object对象有个特殊的方法:hashcode(), hashcode()表示的是JVM虚拟机为这个Object对象分配的一个int类型的数值,JVM会使用对象的hashcode值来 ...