zoukankan      html  css  js  c++  java
  • Zookeeper作业题--实现简易版配置中心

    需求

    基于Zookeeper实现简易版配置中心要求实现以下功能:

    1. 创建一个Web项目,将数据库连接信息交给Zookeeper配置中心管理,即:当项目Web项目启动时,从Zookeeper进行MySQL配置参数的拉取

    2. 要求项目通过数据库连接池访问MySQL(连接池可以自由选择熟悉的)

    3. 当Zookeeper配置信息变化后Web项目自动感知,正确释放之前连接池,创建新的连接池

     需求分析

    1.启动SpringBoot项目,启动时,从Zookeeper拉取配置信息

    2.获取配置,创建对应的数据库连接池,访问mysql

    3.注册监听Zookeeper对应节点数据变化,发生变化时,释放连接池 或 创建新的连接池。重复2的步骤。

    实现代码

    1.maven配置

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>com.zaxxer</groupId>
                <artifactId>HikariCP</artifactId>
                <version>3.4.5</version>
                <scope>compile</scope>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.11</version>
            </dependency>
    
            <!-- zookeeper -->
            <dependency>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
                <version>3.4.14</version>
            </dependency>
            <dependency>
                <groupId>com.101tec</groupId>
                <artifactId>zkclient</artifactId>
                <version>0.2</version>
            </dependency>
    
        </dependencies>

    2.SpringBoot代码

    package com.donaldy.zkpractice;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    import lombok.Data;
    import lombok.ToString;
    import org.I0Itec.zkclient.IZkDataListener;
    import org.I0Itec.zkclient.ZkClient;
    import org.I0Itec.zkclient.exception.ZkMarshallingError;
    import org.I0Itec.zkclient.serialize.ZkSerializer;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    @SpringBootApplication
    public class Application {
    
        private static HikariDataSource hikariDataSource;
    
        private static ZkClient zkClient;
    
        private static ObjectMapper mapper = new ObjectMapper();
    
        /**
         * 启动服务
         * 
         * 1. 启动 web 容器
         * 2. 初始化 zookeeper
         * 3. 配置数据库连接池
         * 
         * @param args 参数
         */
        public static void main(String[] args) {
    
            SpringApplication.run(Application.class, args);
    
            initZk();
    
            configHikariSource();
        }
    
        private static void initZk() {
    
            zkClient = new ZkClient("172.16.64.121:2181");
    
            zkClient.setZkSerializer(new ZkStrSerializer());
    
            zkClient.subscribeDataChanges("/jdbc", new IZkDataListener() {
    
                public void handleDataChange(String path, Object data) {
    
                    System.out.println(path + " data is changed, new data " + data);
    
                    hikariDataSource.close();
    
                    configHikariSource();
                }
    
                public void handleDataDeleted(String path) {
    
                    System.out.println(path + " is deleted!!");
    
                    hikariDataSource.close();
                }
            });
        }
    
        /**
         * 配置数据库连接池
         * 
         * 1. 从 zookeeper 中获取配置信息
         * 2. 更新 hikari 配置
         * 3. 执行测试 sql
         */
        private static void configHikariSource(){
    
            JDBCConfig myConfig = getJDBCConfig();
    
            updateHikariConfig(myConfig);
    
            try {
    
                executeTestSQL();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        private static void executeTestSQL() throws SQLException {
            
            Connection connection = hikariDataSource.getConnection();
    
            PreparedStatement pst = connection.prepareStatement( "SELECT id, username FROM user;" );
    
            ResultSet rs = pst.executeQuery();
    
            while (rs.next()) {
    
                System.out.println("id : " + rs.getString(1) + " , username : " + rs.getString(2));
            }
        }
    
        private static void updateHikariConfig(JDBCConfig myConfig) {
    
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl(myConfig.getUrl());
            config.setUsername(myConfig.getUsername());
            config.setPassword(myConfig.getPassword());
            config.addDataSourceProperty( "driverClassName" , myConfig.getDriver());
            config.addDataSourceProperty( "cachePrepStmts" , "true" );
            config.addDataSourceProperty( "prepStmtCacheSize" , "250" );
            config.addDataSourceProperty( "prepStmtCacheSqlLimit" , "2048" );
            hikariDataSource = new HikariDataSource(config);
        }
    
        private static JDBCConfig getJDBCConfig() {
    
            Object data = zkClient.readData("/jdbc");
    
            try {
                JDBCConfig myConfig = mapper.readValue(data.toString(), JDBCConfig.class);
    
                System.out.println(myConfig.toString());
                
                return myConfig;
                
            } catch (JsonProcessingException e) {
                
                return new JDBCConfig();
            }
        }
    }
    
    class ZkStrSerializer implements ZkSerializer {
    
        @Override
        public byte[] serialize(Object o) throws ZkMarshallingError {
            return String.valueOf(o).getBytes();
        }
    
        @Override
        public Object deserialize(byte[] bytes) throws ZkMarshallingError {
            return new String(bytes);
        }
    }
    
    @Data
    @ToString
    class JDBCConfig {
    
        private String url;
    
        private String driver = "com.mysql.jdbc.Driver";
    
        private String username;
    
        private String password;
    }

    结果展示

    1.在zk中创建节点

    create /jdbc {"url":"jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false","username":"root","password":"root","driver":"com.mysql.jdbc.Driver"}

    2.更改节点中的数据

    # 驱动:改变为 com.mysql.cj.jdbc.Driver
    # 因为 mysql 版本使用 8.0
    
    set /jdbc {"url":"jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false","username":"root","password":"root","driver":"com.mysql.cj.jdbc.Driver"}

    3.删除数据

    delete /jdbc

    运行结果

  • 相关阅读:
    角色总结
    cookie
    基础php链接SQL数据库
    html
    PHP 每天的总结(1)
    php的特性
    [转载]CS0234: 命名空间“System.Data”中不存在类型或命名空间名称“OracleClien...
    [转载]数据库镜像中证书过期的解决方案
    华师大陈默老师的育儿讲
    [转载]如何使用VMware Workstation 8将物理机转换为虚拟机?
  • 原文地址:https://www.cnblogs.com/aloneme/p/14957288.html
Copyright © 2011-2022 走看看