1.前言
数据发布/订阅系统,即所谓的配置中心,顾名思义就是发布者将数据发布到Zookeeper的一个或一系列节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中管理和数据的动态更新。
发布订阅一般有两种模式,分别是推(Push)和拉(Pull)模式。在推拉模式中,服务端主动将数据更新发送给所有订阅的客户端;而拉模式则是客户端主动发起请求来获取最新数据。Zookeeper采取推和拉相结合的方式:客户端会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据。
“配置管理”的实际案例来展示Zookeeper在"数据发布/订阅"场景下的使用方式。
2.案例
将敏感的配置信息存放与Zookeeper中。启动项目时,自动从Zookeeper中获取。
Maven坐标:
12 5org.springframework.boot 3spring-boot-starter-web 46 9org.springframework.boot 7spring-boot-starter-jdbc 810 14org.projectlombok 11lombok 12true 1315 19org.apache.zookeeper 16zookeeper 173.4.10 1820 24org.apache.curator 21curator-framework 222.9.0 2325 29org.apache.curator 26curator-recipes 272.9.0 2830 34org.mybatis 31mybatis 323.4.3 3335 39org.mybatis 36mybatis-spring 371.3.1 3840 43mysql 41mysql-connector-java 4244 48com.zaxxer 45HikariCP 462.7.4 4749 org.springframework.boot 50spring-boot-starter-test 51test 52
自动从Zookeeper中获取”配置信息“,并放入Enviroment中
配置ApplicationContextInitializer,项目在启动先调用该类,进行加载环境变量到Enviroment中去(这里采用在classpath路径下新建META-INF/spring.factories文件方式,其它两种方式为:
1.使用SpringApplication 对象,调用 addInitializers()
2.在配置文件中配置 context.initializer.classes =xx)
spring.factories文件
1 # Initializers2 org.springframework.context.ApplicationContextInitializer=\3 com.example.zkconfig.config.GlobalConfigInit
GlobalConfigIn类进行一系列配置文件加载及Zk连接,我用的Curator框架 我的application.properties此刻内容
server.port=8076#zk 配置信息com.unconfig.info=/config/zk-config
application-dev 则对应具体连接机器
#zkcom.zookeeper.url=zk://192.168.159.129:2181
从zk取配置信息放入spring环境
1 @Slf4j 2 public class GlobalConfigInit implements ApplicationContextInitializer{ 3 4 @Override 5 public void initialize(ConfigurableApplicationContext configurableApplicationContext) { 6 ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment(); 7 String zkUri = environment.getProperty("com.zookeeper.url"); 8 if (null == zkUri) { 9 log.warn("could not find zk uri,unconf not configured..");10 } else {11 ZookeeperUtils zookeeperUtils = new ZookeeperUtils();12 zookeeperUtils.setZkUri(zkUri);13 String unconf = environment.getProperty("com.unconfig.info");14 if (null != unconf) {15 log.info("config uniconf .. {}", unconf);16 ZkPropertySource propertySource = new ZkPropertySource("default", zookeeperUtils.getEnv(unconf));17 environment.getPropertySources().addLast(propertySource);18 } else {19 log.warn("unconf not configured..");20 }21 }22 }23 24 public String getEnv(Environment environment) {25 String zkUrl = environment.getProperty("com.zookeeper.url");26 if (null != zkUrl && !zkUrl.isEmpty()) {27 return zkUrl;28 } else {29 String unConfig = environment.getProperty("com.unconfig.info");30 if (unConfig != null && !unConfig.isEmpty()) {31 ZookeeperURI parse = ZookeeperURI.parse(unConfig);32 String inferZkUrl = "zk://" + parse.getServers();33 System.setProperty("com.zookeeper.url", inferZkUrl);34 log.info("inferred zk uri from unconf zk {}", inferZkUrl);35 return inferZkUrl;36 } else {37 return null;38 }39 }40 }41 }
这里不再多说,接下来配置数据源。
1 @Configuration 2 @MapperScan(basePackages = {"com.example.zkconfig.dao.write"}, sqlSessionFactoryRef = "writeSqlSessionFactory") 3 public class WriteDataSourceConfig { 4 5 @Value("${write.datasource.mappers}") 6 private String location; 7 8 @Bean(name = "writeDataSource") 9 @ConfigurationProperties(prefix = "write.datasource")10 public DataSource dataSource() {11 return DataSourceBuilder.create().type(HikariDataSource.class).build();12 }13 14 @Bean(name = "writeSqlSessionFactory")15 public SqlSessionFactory writeSqlSessionFactory(@Qualifier("writeDataSource") DataSource dataSource) throws Exception {16 SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();17 sqlSessionFactoryBean.setDataSource(dataSource);18 sqlSessionFactoryBean.setMapperLocations(19 new PathMatchingResourcePatternResolver().getResources(location));20 return sqlSessionFactoryBean.getObject();21 }22 23 @Bean(name = "writeTransactionManager")24 public DataSourceTransactionManager writeTransactionManager(@Qualifier("writeDataSource") DataSource dataSource) {25 return new DataSourceTransactionManager(dataSource);26 }27 }
而我实际在zookeeper节点配置的数据
测试走一波,启动成功。