springboot整合nacos动态获取druid配置

摘要:
在完成这个小演示之前,我查看了许多示例和博客,但没有找到任何符合我需求的内容。所以我走了很多弯路来完成这个演示。现在让我们来看看如何实现spring boot+nacos+druid来动态获取数据库配置信息。在我们开始解释演示之前,让我们先看看什么是nacons。dataId=nacos测试演示&group=DEFAULT_group“返回结果:Spring boot集成了nacos和druid,这是今天的重点。但我仍然想直接进入代码。我将为需要解释的内容添加解释。

前言

是不是还有好多小伙伴不知道nacos是啥?其实,我也是从上一次nacos爆出漏洞,才知道还有nacos这个组件,而且目前这个组件应用很广泛,很多项目都用它来做配置中心和注册中心,今天我们分享的内容就是nacos作为配置中心使用的一个小demo

在完成这个小demo之前,我查了好多示例和博客,但是都没有找到符合我需求的,所以走了好多弯路,才让这个demo完整的跑起来,现在我们就来看下如何实现springboot+nacos+druid动态获取数据库配置信息。

今天的demo内容比较多,如果你恰好在学习nacos,认真看完,肯定会有收获。

正文

nacos是什么

在开始讲解这个demo之前,我们先看下什么是naconsnacos是阿里巴巴的一个开源项目,官网给它的定义是:

一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

springboot整合nacos动态获取druid配置第1张

也就是说,它可以实现动态的服务发现,能够实现配置管理,可以作为服务管理平台,简介就到这里,更多信息直接去看官方文档:

https://nacos.io/zh-cn/docs/what-is-nacos.html

springboot整合nacos动态获取druid配置第2张

如何使用nacos

了解它的目的,主要还是为了在我们的项目中使用它,所以我们直接来看如何使用它。

下载nacos

进入官网,点击前往github,你需要去nacosGitHub发布列表中下载,不清楚的小伙伴直接访问下面的网址进入下载页:

https://github.com/alibaba/nacos/releases

最新版本是2.0.0-BETA,是个测试版本,目前最新的稳定版本是1.4.0,本次示例也是这个版本springboot整合nacos动态获取druid配置第3张

点击Assets,选择.zip文件,然后应该就开始下载了,下载可能比较慢

springboot整合nacos动态获取druid配置第4张

解压zip文件

zip文件结构是这样的,直接解压就行,也不需要配置环境变量

springboot整合nacos动态获取druid配置第5张

运行启动nacos服务

进入nacosbin目录,打开cmd窗口,linux打开sh窗口,执行如下命令:

windos环境:

cmd startup.cmd -m standalone

linux环境:

sh startup.sh -m standalone

如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

bash startup.sh -m standalone

其中,standalone表示单机模式,如果不加这个参数,默认是以集群模式运行的(cluster

关闭nacos服务

Linux/Unix/Mac
sh shutdown.sh
Windows
cmd shutdown.cmd

或者双击shutdown.cmd运行文件。

服务注册&发现和配置管理

这里的内容,我直接copy的官网文档,大概看一下就可以了,和示例关系不大。下面的命令就是通过http接口的方式,注册服务、发现服务、发布配置和获取配置。

服务注册
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
服务发现
curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
发布配置
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"
获取配置
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"

修改nacos服务端配置信息

springboot整合nacos动态获取druid配置第6张

这个配置文件里面还可以设置nacos的数据存储,默认的数据存储是derby,这是个完全用java编写的数据库,非常小巧,核心部分derby.jar只有2M,所以既可以做为单独的数据库服务器使用,也可以内嵌在应用程序中使用。如果要启用mysql,可以修改相关配置文件,进行启用:

springboot整合nacos动态获取druid配置第7张

访问nacos服务

如果没有修改nacos的配置,直接浏览器打开如下地址即可,如果修改了端口,需要把端口改成你修改的端口:

http://127.0.0.1:8848/nacos

springboot整合nacos动态获取druid配置第8张

默认用户名和密码都是nacos,登陆成功之后就可以发布你的配置信息了。

发布配置信息

因为我已经加过配置信息了,如果是第一次访问,应该是没有配置信息的。点击右边的+号进行创建

springboot整合nacos动态获取druid配置第9张

输入data-id,必须唯一,类似于主键,不能重复;选择配置格式,这里我选择properties;然后点击发布,一个配置信息就发布成功了

springboot整合nacos动态获取druid配置第10张

springboot整合nacos动态获取druid配置第11张

我们现在来测试下,我们用如下命令:

curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos-test-demo&group=DEFAULT_GROUP"

返回结果:

springboot整合nacos动态获取druid配置第12张

springboot整合nacos和druid

这里才是今天的重点,但是我还是想直接上代码,需要解释的地方,我会补充说明的。

创建springboot项目

引入如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.21</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

除了spring-boot-start-web外,我们引入了spring-cloud-starter-alibaba-nacos-config,这个是nacos的依赖,剩下的就是数据库哈数据源相关的依赖了。

增加nacos配置文件

spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        prefix: springboot-nacos-demo
        file-extension: yaml
        username: nacos
        password: nacos

  profiles:
    active: dev

其中,server-addrnacos的服务地址,如果要修改服务端口的话,可以进入conf找到application.properties进行修改,详细修改过程看前面的内容;

prefixnacos服务中配置的data-id的前缀,和file-extensionprofiles.active最终组合成data-id

file-extension表示文件扩展名,目前支持propetiesYAML,因为springboot目前只支持这两种配置文件,当然nacos本身支持多种配置文件:TEXTJSONXMLYAMLHTMLProperties

usernamenacos服务端的登陆用户名;passwordnacso服务端的登陆密码。profilesspringboot的配置,这里不讲。

发布数据源配置

我这里的数据源密码是加密的,如果你不想加密,删除connection-properties配置,password改成明文密码就可以了,如果你也想加密,可以参考我之前发过的文章:spring boot基于DRUID数据源密码加密及数据源监控实现

spring:
  #阿里巴巴druid数据源配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    sql-script-encoding: utf-8
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      url: jdbc:mysql://127.0.0.1:3307/userlogin?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai
      password: Y2YOft/vPjw/JFPkevqZZKi8pCHu5ambR2ivSxgipTbL76pOoxNw3Un5Hcarbe9AqUImr+wS7YI6TjJZOVYjzA==
      connection-properties: config.decrypt=true;config.decrypt.key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJI/xqbyvpVttxfAKulKeSTIb7tZAGaFcPyTnE2r7AHTQ8kOnqKXDda4u59umt9XBFxi7db28KxeVooB138zuRUCAwEAAQ==
      filter:
        config:
          enabled: true
      # 连接池的配置信息
      # 初始化时建立物理连接的个数
      initial-size: 3
      # 连接池最小连接数
      min-idle: 3
      # 连接池最大连接数
      max-active: 20
      # 获取连接时最大等待时间,单位毫秒
      max-wait: 60000
      # 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
      test-while-idle: true
      # 既作为检测的间隔时间又作为testWhileIdel执行的依据
      time-between-connect-error-millis: 60000
      # 销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
      min-evictable-idle-time-millis: 30000
      # 用来检测连接是否有效的sql 必须是一个查询语句
      # mysql中为 select 'x'
      # oracle中为 select 1 from dual
      validationQuery: select 'x'
      # 申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
      test-on-borrow: false
      # 归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
      test-on-return: false
      # 是否缓存preparedStatement,mysql5.5+建议开启
      pool-prepared-statements: true
      # 当值大于0时poolPreparedStatements会自动修改为true
      max-pool-prepared-statement-per-connection-size: 20
      # 合并多个DruidDataSource的监控数据
      use-global-data-source-stat: false
      # 配置扩展插件
      #监控统计拦截的filters
      filters: stat,wall,slf4j
      # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
      connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      # 定时输出统计信息到日志中,并每次输出日志会导致清零(reset)连接池相关的计数器。
      time-between-log-stats-millis: 300000
      # 配置DruidStatFilter
      web-stat-filter:
        enabled: true
        url-pattern: '/*'
        exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*'
      # 配置DruidStatViewServlet
      stat-view-servlet:
        # 是否启用StatViewServlet(监控页面)默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)
        enabled: true
        url-pattern: '/druid/*'
        # IP白名单(没有配置或者为空,则允许所有访问)
        allow: 127.0.0.1,192.168.0.1
        # IP黑名单 (存在共同时,deny优先于allow)
        deny: 192.168.0.128
        # 禁用HTML页面上的“Reset All”功能
        reset-enable: false
        # 登录名
        login-username: admin
        # 登录密码
        login-password: admin

这些配置文件发布到nacos中:

data-id我前面说了,已经很清楚了。

springboot整合nacos动态获取druid配置第13张

自定义DruidDatasouceWrapper

DruidDatasouceWrapper要继承DruidDataSource

RefreshScope的作用是实现配置、实例热加载,也就是我们重写修改配置信息后,spring会销毁当前类的实例,然后重新创建一个新的实例放到容器中,也是实现数据源配置实时更新的关键

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;

/**
 * @program: springboot-nacos-demo
 * @description:
 * @author: syske
 * @create: 2021-02-28 11:33
 */
@Configuration
@RefreshScope
public class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {
    @Value("${spring.datasource.druid.url}")
    private String url;
    @Value("${spring.datasource.druid.username}")
    private String username;
    @Value("${spring.datasource.druid.password}")
    private String password;
    @Value("${spring.datasource.druid.driver-class-name}")
    private String driverClassName;
    @Value("${spring.datasource.druid.connection-properties}")
    private String connectionProperties;

    private String passwordCallbackClassName;

    public void setMaxWait(int maxWait) {
        this.maxWait = maxWait;
    }

    public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    }

    public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    }

    @Override
    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    @Override
    public void setConnectionProperties(String connectionProperties) {
        this.connectionProperties = connectionProperties;
    }

    @Override
    public void setPasswordCallbackClassName(String passwordCallbackClassName) {
        this.passwordCallbackClassName = passwordCallbackClassName;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 如果未找到前缀“spring.datasource.druid”JDBC属性,将使用“Spring.DataSource”前缀JDBC属性。
        super.setUrl(url);
        super.setUsername(username);
        super.setPassword(password);
        super.setDriverClassName(driverClassName);
        super.setInitialSize(initialSize);
        super.setMinIdle(minIdle);
        super.setMaxActive(maxActive);
        super.setMaxWait(maxWait);
        super.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        super.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        super.setValidationQuery(validationQuery);
        super.setTestWhileIdle(testWhileIdle);
        super.setTestOnBorrow(testOnBorrow);
        super.setTestOnReturn(testOnReturn);
        super.setPoolPreparedStatements(poolPreparedStatements);
        super.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        super.setConnectionProperties(connectionProperties);
        super.setDbType(dbType);
        super.setPasswordCallbackClassName(passwordCallbackClassName);
    }
}

配置nacos

这里关键的配置就一个,EnableAutoConfiguration启动springboot的自动自动配置,下面的方法是在初始化的时候,创建数据源实例,同样也启用了热加载

import com.alibaba.druid.pool.DruidDataSource;
import io.github.syske.springbootnacosdemo.druidconfig.DruidDataSourceWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Nacos配置
 */
@EnableAutoConfiguration
@Configuration
public class NacosConfigConfiguration {
    private final Logger LOGGER = LoggerFactory.getLogger(NacosConfigConfiguration.class);

    @Bean(initMethod = "init")
    @ConditionalOnMissingBean
    @RefreshScope
    public DruidDataSource dataSource() {
        LOGGER.info("Init DruidDataSource");
        return new DruidDataSourceWrapper();
    }
}

测试

到这里,核心代码就全部完了,我们启动demo测试下:

springboot整合nacos动态获取druid配置第14张

如上日志信息,我们可以看到springboot启动的时候加载了nacos发布的配置信息,然后还会有数据源初始成功的提示信息:

springboot整合nacos动态获取druid配置第15张

然后我们写一个controller测试下:

@RestController
public class TestController {

    @Autowired
    private DruidDataSourceWrapper dataSourceWrapper;

    @RequestMapping("/test")
    public String testDruid() throws SQLException {
        DruidPooledConnection connection = dataSourceWrapper.getConnection();
        Statement statement = connection.createStatement();
        ResultSet  resultSet = statement.executeQuery("SELECT * from user;");
        System.out.println(resultSet);
        while(resultSet.next()){
            System.out.println(resultSet.getString("username"));
        }
        return "hello druid";
    }
}

我这里有两个数据库,都有user表,我现在的数据库地址配的是userlogin这个库,我先访问下,后台打印信息如下:

springboot整合nacos动态获取druid配置第16张

然后我们将数据库改成my_db_test,然后发布配置,再次访问:

springboot整合nacos动态获取druid配置第17张

配置发布完成后,springboot后台已经打印了配置更新的日志,说明配置已经被刷新:

springboot整合nacos动态获取druid配置第18张

然后我们再访问:

springboot整合nacos动态获取druid配置第19张

从日志记录来看,我们再次访问的时候,数据源重新初始化,当然最后打印的结果也和我们预期的一样,打印了我们刚加的配置对应的数据表里面的用户信息。当然再改回,也是可以的:

springboot整合nacos动态获取druid配置第20张

springboot整合nacos动态获取druid配置第21张

再次访问:

springboot整合nacos动态获取druid配置第22张

而且后台也有数据库url修改的提示信息

结语

好了,今天的内容就到这里吧,本次实例比较完整的介绍了springboo + nacos + druid实现动态获取数据库配置的构建过程,同时也比较详细的说明了nacos的相关配置,我觉得很完美,至少我很满意。关于这个demo,我上周就在弄,但是项目一直跑不起来,也没有参考的样例,所以就搁置着,今天总算搞定了,很奈斯哦。下面是demo的完整代码获取地址:

https://github.com/Syske/learning-dome-code/tree/dev/springboot-nacos-demo

免责声明:文章转载自《springboot整合nacos动态获取druid配置》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇解决IE升级后必须以管理员运行的问题Jmeter下载时Binaries和Source两类包的区别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

微软CRM系统二次开发步骤以及注意事项

微软CRM系统的二次开发主要包括四个方面:1)自定义实体的设置;2):站点图的设置;3)ISV.Config文件(实体页面导航条以及功能菜单)的配置;4)客户端JavaScript的设计。 特别注意:对系统中进行的二次开发之后一定要在自定义界面选择“发布”,不然是不能使用的。 一:自定义实体的设置 微软CRM系统提供按照自己需求要求,对CRM系统功能进行扩...

java property 配置文件管理工具框架,避免写入 property 乱序

property property 是 java 实现的 property 框架。 特点 优雅地进行属性文件的读取和更新 写入属性文件后属性不乱序 灵活定义编码信息 使用 OO 的方式操作 property 文件 支持多级对象引用 变更日志 ChangeLog 快速开始 环境依赖 Maven 3.x Jdk 1.7+ Maven 引入依赖 <de...

java通过jdbc连接数据库并更新数据(包括java.util.Date类型数据的更新)

一、步骤 1.获取Date实例,并通过getTime()方法获得毫秒数; 2.将获取的毫秒数存储到数据库中,注意存储类型为nvarchar(20); 3.读取数据库的毫秒数,作为Date构造方法的参数创建实例,有需要再转换时间格式。 二、代码示例 packagecom.yh.dao; importjava.sql.Connection; importja...

ngx_lua 随笔

--[[ test--]]ngx.header.content_type = "text/plain"; --输出头部local user = ngx.var.arg_user -- 定义user变量并获取url中的参数 http://localhost?user=hellolocal sys = ngx.var.server_name -- 获取ngi...

WPF: 在ListView中添加Checkbox列表

描述:ListView是WPF中动态绑定工具的数据容器,本文实现了一个在ListView中显示的供用户选择的列表项目,并且控制列表中选择的项目数量,即实现单选。 XAML中创建ListView,代码如下: <ListView x:Name="listView_LineOfBusiness" Width="280" Height="220">...

EasySharding.EFCore 如何设计使用一套代码完成的EFCore Migration 构建Saas系统多租户不同业务需求且满足租户自定义分库分表、数据迁移能力?

下面用一篇文章来完成这些事情 多租户系统的设计单纯的来说业务,一套Saas多租户的系统,面临很多业务复杂性,不同的租户存在不同的业务需求,大部分相同的表结构,那么如何使用EFCore来完成这样的设计呢?满足不同需求的数据库结构迁移 这里我准备设计一套中间件来完成大部分分库分表的工作,然后可以通过自定义的Migration 数据库文件来迁移构建不同的租户数据...