基于SPI机制修改ShardingJDBC底层,实现Nacos配置数据源

  目前最新版本的ShardingJdbc中,没有支持基于Nacos作为配置数据源的功能,经过阅读源码,发现ShardingJdbc底层是基于SPI机制来扫描的,所以决定对ShardingJdbc进行二次开发,使其可以支持Nacos的动态配置功能。

  从shardingsphere-jdbc-core的 jar 包中可以发现,有些类似于SPI机制。于是开始推测,这个地方是不是可以做二次开发。

在这里插入图片描述

  接着,根据这份SPI文件内部记录的类名,可以深入进行观察,发现它们都存在相同的接口。在接口中定义了acceptgetContent函数,这两个函数从实现类的逻辑上看,感觉是在根据 url 的格式去判断用哪个 URLProvider 读取配置。

在这里插入图片描述
  为了验证这个逻辑是否正确,在ClasspathDriverURLProvider的accept处加入断点进行观察。
在这里插入图片描述
  这里会发现,在org.apache.shardingsphere.driver.jdbc.core.driver.ShardingSphereDriverURLManager中有一个do-while循环,它会将spi文件中的所有类都进行一次校验,如果accept返回成功,那么就会使用匹配的URLProvider对象去进行配置的进一步读取。代码如下图所示:
在这里插入图片描述
  所以基本上,我们看到了这里,基本上可以想到设计思路了,自定义一个扩展类,也是采用SPI的思路去实现,在新定义的扩展类中实现对nacos的相关配置读取,然后在getContent函数中返回出去。接下来进行二次开发设计。

基于ShardingSphereDriverURLProvider接口实现SPI扩展类

  1. 这里需要用到关于shardingjdbc和nacos的依赖,相关依赖配置如下:
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core</artifactId>
    <version>5.3.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
</dependency>
  1. 在golive-framework-datasource-starter模块中,编写一个基于Nacos配置的类,代码内容如下:
package org.golive.framework.datasource.starter.config;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.driver.jdbc.core.driver.ShardingSphereDriverURLProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.module.Configuration;
import java.util.Properties;

public class NacosDriverURLProvider implements ShardingSphereDriverURLProvider {

    private static Logger logger = LoggerFactory.getLogger(NacosDriverURLProvider.class);
    private static final String NACOS_TYPE = "nacos:";
    private static final String GROUP = "DEFAULT_GROUP";

    @Override
    public boolean accept(String url) {
        return StringUtils.isNotBlank(url) && url.contains(NACOS_TYPE);
    }

    /**
     * 从url中获取到nacos的连接配置信息
     */
    @Override
    public byte[] getContent(final String url) {
        if (StringUtils.isEmpty(url)) {
            return null;
        }
        // 得到例如:golive.nacos.com:8848:golive-user-shardingjdbc.yaml?username=nacos&&password=nacos&&namespace=golive-test 格式的url
        String nacosUrl = url.substring(url.lastIndexOf(NACOS_TYPE) + NACOS_TYPE.length());
        /**
         * 得到三个字符串,分别是:
         * golive.nacos.com
         * 8848
         * golive-user-shardingjdbc.yaml
         */
        String nacosStr[] = nacosUrl.split(":");
        String nacosFileStr = nacosStr[2];
        /**
         * 得到两个字符串
         * golive-user-shardingjdbc.yaml
         * username=nacos&&password=nacos&&namespace=golive-test
         */
        String nacosFileProp[] = nacosFileStr.split("\\?");
        String dataId = nacosFileProp[0];
        String acceptProp[] = nacosFileProp[1].split("&&");
        // 从这里获取到
        Properties properties = new Properties();
        properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosStr[0] + ":" + nacosStr[1]);
        for (String propertyName : acceptProp) {
            String[] propertyItem = propertyName.split("=");
            String key = propertyItem[0];
            String value = propertyItem[1];
            if ("username".equals(key)) {
                properties.setProperty(PropertyKeyConst.USERNAME, value);
            } else if ("password".equals(key)) {
                properties.setProperty(PropertyKeyConst.PASSWORD, value);
            } else if ("namespace".equals(key)) {
                properties.setProperty(PropertyKeyConst.NAMESPACE, value);
            }
        }
        ConfigService configService = null;
        try {
            configService = NacosFactory.createConfigService(properties);
            String content = configService.getConfig(dataId, GROUP, 6000);
            logger.info(content);
            return content.getBytes();
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }
}
  1. 遵循shardingjdbc的spi机制,创建/META-INF/services/org.apache.shardingsphere.driver.jdbc.core.driver.ShardingSphereDriverURLProvider文件,然后在里面写上我们上边的这个NacosDriverURLProvider类的全路径地址。
org.golive.framework.datasource.starter.config.NacosDriverURLProvider
  1. 编写完上述内容后,整个模块基本如下图所示:

在这里插入图片描述
最后,修改在nacos的golive-user-provider.yaml中配置的shardingjdbc配置url参数为:

jdbc:shardingsphere:nacos:ip地址:8848:golive-user-shardingjdbc.yaml?username=nacos&&password=nacos&&namespace=golive-test

放上golive-user-shardingjdbc.yaml配置文件内容:

dataSources:
  user_master: ##新表,重建的分表
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://ip地址:8808/qiyu_live_user?useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root
  user_slave0: ##新表,重建的分表
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://ip地址:8809/qiyu_live_user?useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root
rules:
    - !READWRITE_SPLITTING
      dataSources:
        user_ds:
          staticStrategy:
            writeDataSourceName: user_master
            readDataSourceNames:
              - user_slave0
    - !SINGLE
      defaultDataSource: user_ds # 不分表分分库的默认数据源
    - !SHARDING
      tables:
        t_user:
          actualDataNodes: user_ds.t_user_${(0..99).collect(){it.toString().padLeft(2,'0')}}
          tableStrategy:
            standard:
              shardingColumn: user_id
              shardingAlgorithmName: t_user-inline
        t_user_tag:
          actualDataNodes: user_ds.t_user_tag_${(0..99).collect(){it.toString().padLeft(2,'0')}}
          tableStrategy:
            standard:
              shardingColumn: user_id
              shardingAlgorithmName: t_user_tag-inline
      shardingAlgorithms:
        t_user-inline:  # 路由规则 : t_user分表
          type: INLINE
          props:
            algorithm-expression: t_user_${(user_id % 100).toString().padLeft(2,'0')}
        t_user_tag-inline: # 路由规则 : t_user_tag分表
          type: INLINE
          props:
            algorithm-expression: t_user_tag_${(user_id % 100).toString().padLeft(2,'0')}
props:
  sql-show: true
  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
nacos支持双数据源配置,可以通过在配置文件中添加第二个数据源配置实现。具体步骤如下: 1. 配置文件中添加第二个数据源配置,包括驱动类名、连接地址、用户名和密码等信息。例如: ```yaml spring: datasource: datasource1: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/db1 username: root password: 123456 datasource2: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3307/db2 username: root password: 123456 ``` 2. 在项目中使用`@Configuration`注解创建一个配置类,用于配置数据源。在该类中创建两个数据源的`DataSource`对象,并将其注入到`Spring`容器中。例如: ```java @Configuration public class DataSourceConfig { @Bean(name = "datasource1") @ConfigurationProperties(prefix = "spring.datasource.datasource1") public DataSource dataSource1() { return DataSourceBuilder.create().build(); } @Bean(name = "datasource2") @ConfigurationProperties(prefix = "spring.datasource.datasource2") public DataSource dataSource2() { return DataSourceBuilder.create().build(); } } ``` 3. 在需要使用数据源的地方,通过`@Qualifier`注解指定使用哪个数据源。例如: ```java @Autowired @Qualifier("datasource1") private DataSource datasource1; @Autowired @Qualifier("datasource2") private DataSource datasource2; ``` 以上是配置nacos数据源的方法。通过在配置文件中添加第二个数据源配置,然后在项目中创建对应的数据源对象,并将其注入到Spring容器中,就可以实现数据源配置了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值