Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>nacos-druid-example</artifactId>
<name>Spring Cloud Starter Alibaba Nacos Config Proxy Druid Example</name>
<description>Example demonstrating how to use nacos config to proxy druid</description>
<packaging>jar</packaging>

<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>

<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 数据库驱动,以MySQL为例 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
<scope>runtime</scope>
</dependency>
<!-- Druid连接池, 包括Spring Starter及druid内核版本 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.27</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.27</version>
</dependency>
<!-- 商业化kms加解密插件 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client-mse-extension</artifactId>
<version>1.0.6</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Nacos Proxy Druid动态数据源

## 项目说明

本项目介绍如何使用 Spring Cloud Alibaba Nacos Config 代理Druid数据源,实现应用的数据源配置运行时无损轮转 。

[Nacos](https://github.com/alibaba/Nacos) 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

## 购买 MSE Nacos企业版

商业化MSE Nacos数据源管理功能,集合KMS实现了对应用访问数据库所需的参数加密托管,包括账号密码,数据库连接池参数等,同时应用侧结合druid实现应用运行时数据源的无损轮转。

###

参照 https://help.aliyun.com/zh/rds/apsaradb-rds-for-mysql/spring-application-rds-data-source-account-password-run-time-rotation 完成数据源创建。

## 应用侧接入示例

### Spring Cloud Alibaba Nacos Config

nacos-druid-example已经完成了基础的访问数据库的接口实例创建以及在application.properties的参数配置。

通过一下脚本创建工程代码访问的数据库表

```
初始化表
CREATE TABLE `demo_entity` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci,
`content` longtext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=199492 DEFAULT CHARSET=utf8mb3

初始化数据
INSERT INTO `demo_entity` (`id`,`name`,`content`) VALUES (123,'testname',null);

```

在MSE Nacos企业版中创建好数据源之后,可以参照应用侧接入中的指引,对application.properties中的配置进行替换即可。

```
# import datasource config to init druid datasource.
spring.config.import[0]=optional:nacos:{替换为数据源配置的DataId}?group=nacos-datasource

# nacos server address, replace it with your own
spring.cloud.nacos.config.server-addr={替换为nacos企业版接入地址,保证本地可正常链接9848端口}
# nacos namespace, replace it with your own
spring.cloud.nacos.config.namespace={替换为nacos企业版数据源所在命名空间ID}

# nacos kms regionId , replace it with your own
spring.cloud.nacos.config.kms_region_id={替换为nacos企业版实例关联KMS的RegionId}

# nacos proxy druid switch and data id
spring.nacos.config.proxy.druid.enabled=true
spring.nacos.config.proxy.druid.data-id={替换为数据源配置的DataId}

```

除以上配置外,需要通过环境变量或者-D JVM参数设置访问Nacos及KMS的凭证

```
-Dspring.cloud.nacos.config.access-key=LTA****************
-Dspring.cloud.nacos.config.secret-key=ot***************
```

按要求设置参数后,运行NacosSpringBootDemoApplication即可。
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package com.alibaba.demo.nacosdruidexample;

import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;

import com.alibaba.demo.nacosdruidexample.dao.JdbcEntityRepository;
import com.alibaba.demo.nacosdruidexample.dao.JpaDemoEntityRepository;
import jakarta.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import static java.util.concurrent.TimeUnit.MILLISECONDS;


@RestController("demo")
public class DemoController {

JpaDemoEntityRepository jpaDemoEntityRepository;

JdbcEntityRepository jdbcEntityRepository;

@Value(value = "${testKey:123}")
private String testKey;

@GetMapping("/getTestKey")
public String getTestKey(HttpServletResponse httpServletResponse) {
return testKey + new Date();
}

DemoController(JpaDemoEntityRepository jpaDemoEntityRepository, JdbcEntityRepository jdbcEntityRepository) {
this.jpaDemoEntityRepository = jpaDemoEntityRepository;
this.jdbcEntityRepository = jdbcEntityRepository;

for (int i = 0; i < 10; i++) {
scheduleTask();
}
}

private void scheduleTask() {
Executors.newScheduledThreadPool(2).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
selectTask();
}
}, 200, 200, MILLISECONDS);
}

private void selectTask() {
int count = 200;
int successCount = 0;
int failCount = 0;
long start = System.currentTimeMillis();
while (count > 0) {
try {
String nameById = jdbcEntityRepository.findNameById(123l);
if (nameById != null) {
successCount++;
}
}
catch (Throwable throwable) {
failCount++;
}
finally {
count--;
}
}

System.out.println(new Date() + ",SuccessCount:" + successCount + ",failCount:" + failCount + ", cost:" + (System.currentTimeMillis() - start) + " ms");

}

private void searchTask() {
int count = 1000;

while (count > 0) {
long start = System.currentTimeMillis();

try {

List<String> nameById = jdbcEntityRepository.getByContent(generateRandomString(1));
if (nameById != null) {
System.out.println("Success, cost:" + (System.currentTimeMillis() - start) + " ms");

}
}
catch (Throwable throwable) {
System.out.println("Fail, cost:" + (System.currentTimeMillis() - start) + " ms");

}
finally {
count--;
}
}
}

private void insertTask() {
int count = 1000;
int successCount = 0;
int failCount = 0;
long start = System.currentTimeMillis();
while (count > 0) {
try {
jdbcEntityRepository.insertNameById(generateRandomString(5), generateRandomString(100_100));

}
catch (Throwable throwable) {
failCount++;
}
finally {
count--;
}
}

System.out.println(new Date() + ",SuccessCount:" + successCount + ",failCount:" + failCount + ", cost:" + (System.currentTimeMillis() - start) + " ms");

}

private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

public static String generateRandomString(int length) {
Random random = new Random();
StringBuilder sb = new StringBuilder(length);

// 从字符集中随机选择字符并追加到 StringBuilder 中
for (int i = 0; i < length; i++) {
int index = random.nextInt(CHARACTERS.length());
sb.append(CHARACTERS.charAt(index));
}

return sb.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.alibaba.demo.nacosdruidexample;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = {"com.alibaba.cloud", "com.alibaba.demo"})
@SpringBootApplication
public class NacosSpringBootDemoApplication {

public static void main(String[] args) {
SpringApplication.run(NacosSpringBootDemoApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.alibaba.demo.nacosdruidexample.dao;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class DemoEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

private String description;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.alibaba.demo.nacosdruidexample.dao;

import java.util.List;

public interface JdbcEntityRepository {

String findNameById(Long id);

void insertNameById(String name, String content);

List<String> getByContent(String content);
}
Loading
Loading