From 41fad5b83123f0fd1095e4ff5e906e017a8ca69d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=92=9F=E5=AE=B6=E5=85=B4?= <2648609927@qq.com>
Date: Thu, 1 May 2025 23:26:22 +0800
Subject: [PATCH] =?UTF-8?q?feat(sa-base):=20=E5=AE=9E=E7=8E=B0=E4=B8=BB?=
=?UTF-8?q?=E4=BB=8E=E6=95=B0=E6=8D=AE=E6=BA=90=E5=8A=A8=E6=80=81=E5=88=87?=
=?UTF-8?q?=E6=8D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 DataSource 注解用于切换数据源
- 实现 DynamicDataSourceHandler 动态数据源处理器
- 添加 DruidConfig 配置多数据源
- 更新 sa-base.yaml 配置文件,支持主从数据源
---
.../sa/base/common/annoation/DataSource.java | 26 +++
.../base/common/aspect/DataSourceAspect.java | 69 ++++++
.../sa/base/config/DataSourceConfig.java | 201 ------------------
.../lab1024/sa/base/config/DruidConfig.java | 87 ++++++++
.../sa/base/constant/DataSourceTypeEnum.java | 23 ++
.../DynamicDataSourceContextHandler.java | 44 ++++
.../handler/DynamicDataSourceHandler.java | 37 ++++
.../sa/base/properties/DruidProperties.java | 73 +++++++
.../src/main/resources/dev/sa-base.yaml | 32 ++-
9 files changed, 380 insertions(+), 212 deletions(-)
create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/annoation/DataSource.java
create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/aspect/DataSourceAspect.java
delete mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DataSourceConfig.java
create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DruidConfig.java
create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/constant/DataSourceTypeEnum.java
create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/handler/DynamicDataSourceContextHandler.java
create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/handler/DynamicDataSourceHandler.java
create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/properties/DruidProperties.java
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/annoation/DataSource.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/annoation/DataSource.java
new file mode 100644
index 00000000..140aa7c6
--- /dev/null
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/annoation/DataSource.java
@@ -0,0 +1,26 @@
+package net.lab1024.sa.base.common.annoation;
+
+import net.lab1024.sa.base.constant.DataSourceTypeEnum;
+
+import java.lang.annotation.*;
+
+/**
+ * 切换数据源名称
+ *
+ * @Author 钟家兴
+ * @Date 2025-05-01 14:49
+ * @Wechat JavaerEngineer
+ * @Email lab1024@163.com
+ * @Copyright 1024创新实验室
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource {
+
+ /**
+ * 切换数据源名称
+ */
+ public DataSourceTypeEnum value() default DataSourceTypeEnum.SLAVE;
+}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/aspect/DataSourceAspect.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/aspect/DataSourceAspect.java
new file mode 100644
index 00000000..1e31e254
--- /dev/null
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/aspect/DataSourceAspect.java
@@ -0,0 +1,69 @@
+package net.lab1024.sa.base.common.aspect;
+
+import net.lab1024.sa.base.common.annoation.DataSource;
+import net.lab1024.sa.base.handler.DynamicDataSourceContextHandler;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+/**
+ * 多数据源处理
+ *
+ * @Author 钟家兴
+ * @Date 2025-05-01 14:49
+ * @Wechat JavaerEngineer
+ * @Email lab1024@163.com
+ * @Copyright 1024创新实验室
+ */
+@Aspect
+@Order(1)
+@Component
+public class DataSourceAspect {
+
+ /**
+ * aop切点,有相关注解的方法才做增强处理
+ */
+ @Pointcut("@annotation(net.lab1024.sa.base.common.annoation.DataSource) || @within(net.lab1024.sa.base.common.annoation.DataSource)")
+ public void dsPointCut() {
+ }
+
+ /**
+ * 环绕通知
+ */
+ @Around("dsPointCut()")
+ public Object around(ProceedingJoinPoint point) throws Throwable {
+ DataSource dataSource = getDataSource(point);
+
+ if (dataSource != null) {
+ DynamicDataSourceContextHandler.setDataSourceType(dataSource.value().name());
+ }
+
+ try {
+ return point.proceed();
+ } finally {
+ DynamicDataSourceContextHandler.clearDataSourceType();
+ }
+ }
+
+ /**
+ * 获取需要切换的数据源
+ */
+ public DataSource getDataSource(ProceedingJoinPoint point) {
+ MethodSignature signature = (MethodSignature) point.getSignature();
+ DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
+
+ // 方法注解为空,则取类注解
+ if (Objects.nonNull(dataSource)) {
+ return dataSource;
+ }
+
+ return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
+ }
+}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DataSourceConfig.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DataSourceConfig.java
deleted file mode 100644
index 24fdc89d..00000000
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DataSourceConfig.java
+++ /dev/null
@@ -1,201 +0,0 @@
-package net.lab1024.sa.base.config;
-
-import com.alibaba.druid.filter.Filter;
-import com.alibaba.druid.filter.stat.StatFilter;
-import com.alibaba.druid.pool.DruidDataSource;
-import com.alibaba.druid.support.jakarta.StatViewServlet;
-import com.alibaba.druid.support.jakarta.WebStatFilter;
-import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
-import com.baomidou.mybatisplus.annotation.DbType;
-import com.baomidou.mybatisplus.core.config.GlobalConfig;
-import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
-import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
-import lombok.extern.slf4j.Slf4j;
-import net.lab1024.sa.base.common.domain.DataScopePlugin;
-import net.lab1024.sa.base.handler.MybatisPlusFillHandler;
-import org.apache.ibatis.plugin.Interceptor;
-import org.apache.ibatis.session.SqlSessionFactory;
-import org.springframework.aop.support.DefaultPointcutAdvisor;
-import org.springframework.aop.support.JdkRegexpMethodPointcut;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.boot.web.servlet.ServletRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Conditional;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
-
-import javax.sql.DataSource;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 数据源配置
- *
- * @Author 1024创新实验室-主任: 卓大
- * @Date 2017-11-28 15:21:10
- * @Wechat zhuoda1024
- * @Email lab1024@163.com
- * @Copyright 1024创新实验室
- */
-@Slf4j
-@Configuration
-public class DataSourceConfig {
-
- @Value("${spring.datasource.driver-class-name}")
- String driver;
-
- @Value("${spring.datasource.url}")
- String url;
-
- @Value("${spring.datasource.username}")
- String username;
-
- @Value("${spring.datasource.password}")
- String password;
-
- @Value("${spring.datasource.initial-size}")
- int initialSize;
-
- @Value("${spring.datasource.min-idle}")
- int minIdle;
-
- @Value("${spring.datasource.max-active}")
- int maxActive;
-
- @Value("${spring.datasource.max-wait}")
- long maxWait;
-
- @Value("${spring.datasource.time-between-eviction-runs-millis}")
- long timeBetweenEvictionRunsMillis;
-
- @Value("${spring.datasource.min-evictable-idle-time-millis}")
- long minEvictableIdleTimeMillis;
-
- @Value("${spring.datasource.filters}")
- String filters;
-
- @Value("${spring.datasource.druid.username}")
- String druidUserName;
-
- @Value("${spring.datasource.druid.password}")
- String druidPassword;
-
- @Value("${spring.datasource.druid.login.enabled}")
- boolean druidLoginEnable;
-
- @Value("${spring.datasource.druid.method.pointcut}")
- String methodPointcut;
-
- @jakarta.annotation.Resource
- private MybatisPlusInterceptor paginationInterceptor;
-
- @jakarta.annotation.Resource
- private DataScopePlugin dataScopePlugin;
-
- @Bean
- @Primary
- public DataSource druidDataSource() {
- DruidDataSource druidDataSource = new DruidDataSource();
- druidDataSource.setDbType(DbType.MYSQL.getDb());
- druidDataSource.setDriverClassName(driver);
- druidDataSource.setUrl(url);
- druidDataSource.setUsername(username);
- druidDataSource.setPassword(password);
- druidDataSource.setInitialSize(initialSize);
- druidDataSource.setMinIdle(minIdle);
- druidDataSource.setMaxActive(maxActive);
- druidDataSource.setMaxWait(maxWait);
- druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
- druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- druidDataSource.setValidationQuery("SELECT 1");
- try {
- druidDataSource.setFilters(filters);
- ArrayList arrayList = new ArrayList<>();
- StatFilter statFilter = new StatFilter();
- statFilter.setMergeSql(true);
- statFilter.setSlowSqlMillis(1000);
- statFilter.setLogSlowSql(true);
- arrayList.add(statFilter);
- druidDataSource.setProxyFilters(arrayList);
- druidDataSource.init();
- } catch (SQLException e) {
- log.error("初始化数据源出错", e);
- }
-
- return druidDataSource;
- }
-
- @Bean
- public SqlSessionFactory sqlSessionFactory() throws Exception {
- MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
- factoryBean.setDataSource(druidDataSource());
- PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- Resource[] resources = resolver.getResources("classpath*:/mapper/**/*.xml");
- factoryBean.setMapperLocations(resources);
-
- // 设置 MyBatis-Plus 分页插件 注意此处myBatisPlugin一定要放在后面
- List pluginsList = new ArrayList<>();
- pluginsList.add(paginationInterceptor);
- if (dataScopePlugin != null) {
- pluginsList.add(dataScopePlugin);
- }
- factoryBean.setPlugins(pluginsList.toArray(new Interceptor[0]));
- // 添加字段自动填充处理
- factoryBean.setGlobalConfig(new GlobalConfig().setBanner(false).setMetaObjectHandler(new MybatisPlusFillHandler()));
-
- return factoryBean.getObject();
- }
-
- /**
- * 非正式环境 才加载
- *
- * @return
- */
- @Conditional(SystemEnvironmentConfig.class)
- @Bean
- public ServletRegistrationBean druidServlet() {
- ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean<>();
- servletRegistrationBean.setServlet(new StatViewServlet());
- servletRegistrationBean.addUrlMappings("/druid/*");
- Map initParameters = new HashMap();
- //不设置用户名密码可以直接通过druid/index.html访问
- if (druidLoginEnable) {
- initParameters.put("loginUsername", druidUserName);
- initParameters.put("loginPassword", druidPassword);
- }
- initParameters.put("resetEnable", "false");
- servletRegistrationBean.setInitParameters(initParameters);
- return servletRegistrationBean;
- }
-
- @Bean
- public FilterRegistrationBean filterRegistrationBean() {
- FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
- filterRegistrationBean.setFilter(new WebStatFilter());
- filterRegistrationBean.addUrlPatterns("/*");
- filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/*");
- return filterRegistrationBean;
- }
-
- @Bean
- public JdkRegexpMethodPointcut jdkRegexpMethodPointcut() {
- JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
- jdkRegexpMethodPointcut.setPatterns(methodPointcut);
- return jdkRegexpMethodPointcut;
- }
-
- @Bean
- public DefaultPointcutAdvisor defaultPointcutAdvisor() {
- DefaultPointcutAdvisor pointcutAdvisor = new DefaultPointcutAdvisor();
- pointcutAdvisor.setPointcut(jdkRegexpMethodPointcut());
- pointcutAdvisor.setAdvice(new DruidStatInterceptor());
- return pointcutAdvisor;
- }
-
-}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DruidConfig.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DruidConfig.java
new file mode 100644
index 00000000..bae70ba3
--- /dev/null
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/DruidConfig.java
@@ -0,0 +1,87 @@
+package net.lab1024.sa.base.config;
+
+import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceBuilder;
+import lombok.extern.slf4j.Slf4j;
+import net.lab1024.sa.base.constant.DataSourceTypeEnum;
+import net.lab1024.sa.base.handler.DynamicDataSourceHandler;
+import net.lab1024.sa.base.properties.DruidProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Druid 配置多数据源
+ *
+ * @Author 钟家兴
+ * @Date 2025-05-01 14:49
+ * @Wechat JavaerEngineer
+ * @Email lab1024@163.com
+ * @Copyright 1024创新实验室
+ */
+@Slf4j
+@Configuration
+public class DruidConfig {
+
+ /**
+ * 这里以map的方式存储所有的自定义的数据源,其中key是枚举类的字符串值,value是创建好且赋值好的数据源对象
+ */
+ private static Map