Procházet zdrojové kódy

修复非动态数据源服务启动异常问题

Woody před 2 měsíci
rodič
revize
55e0f0412e

+ 0 - 36
framework-database/src/main/java/com/chelvc/framework/database/config/DatabaseConfigurer.java

@@ -5,11 +5,6 @@ import java.util.function.Supplier;
 
 import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
 import com.baomidou.mybatisplus.core.injector.ISqlInjector;
-import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
-import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.common.function.Executor;
 import com.chelvc.framework.common.function.Handler;
 import com.chelvc.framework.common.function.Provider;
@@ -27,16 +22,12 @@ import com.chelvc.framework.database.handler.ModificationTypeHandler;
 import com.chelvc.framework.database.handler.PeriodTypeHandler;
 import com.chelvc.framework.database.handler.RangeTypeHandler;
 import com.chelvc.framework.database.handler.RegionTypeHandler;
-import com.chelvc.framework.database.interceptor.CustomizeMybatisInterceptor;
-import com.chelvc.framework.database.interceptor.DeletedIsolateInterceptor;
-import com.chelvc.framework.database.interceptor.EnvIsolateInterceptor;
 import com.chelvc.framework.database.support.EnhanceSqlInjector;
 import lombok.NonNull;
 import org.apache.ibatis.type.JdbcType;
 import org.apache.ibatis.type.TypeHandlerRegistry;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.transaction.annotation.Transactional;
@@ -112,31 +103,4 @@ public class DatabaseConfigurer {
         }
         return handler;
     }
-
-    @Bean
-    public MybatisPlusInterceptor mybatisPlusInterceptor(ApplicationContext applicationContext) {
-        MybatisPlusInterceptor interceptor = new CustomizeMybatisInterceptor(applicationContext);
-
-        // 设置自定义租户隔离拦截器
-        ApplicationContextHolder.getSortBeans(applicationContext, InnerInterceptor.class)
-                .forEach(interceptor::addInnerInterceptor);
-
-        // 设置数据环境隔离过滤拦截器
-        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor() {
-            {
-                this.setTenantLineHandler(new EnvIsolateInterceptor());
-            }
-        });
-
-        // 设置数据逻辑删除过滤拦截器
-        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor() {
-            {
-                this.setTenantLineHandler(new DeletedIsolateInterceptor());
-            }
-        });
-
-        // 设置分页拦截器,数据过滤条件与拦截器设置顺序有关,分页拦截器最后设置才能在分页时同时使用数据隔离过滤条件
-        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
-        return interceptor;
-    }
 }

+ 0 - 97
framework-database/src/main/java/com/chelvc/framework/database/interceptor/CustomizeMybatisInterceptor.java

@@ -1,97 +0,0 @@
-package com.chelvc.framework.database.interceptor;
-
-import java.sql.Connection;
-import java.util.Map;
-import javax.sql.DataSource;
-
-import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
-import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
-import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
-import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
-import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
-import com.chelvc.framework.database.util.SQLUtils;
-import com.google.common.collect.Maps;
-import com.zaxxer.hikari.HikariDataSource;
-import lombok.NonNull;
-import org.apache.ibatis.cache.CacheKey;
-import org.apache.ibatis.executor.Executor;
-import org.apache.ibatis.executor.statement.StatementHandler;
-import org.apache.ibatis.mapping.BoundSql;
-import org.apache.ibatis.mapping.MappedStatement;
-import org.apache.ibatis.plugin.Intercepts;
-import org.apache.ibatis.plugin.Invocation;
-import org.apache.ibatis.plugin.Signature;
-import org.apache.ibatis.session.ResultHandler;
-import org.apache.ibatis.session.RowBounds;
-import org.springframework.context.ApplicationContext;
-
-/**
- * 自定义Mybatis拦截器
- *
- * @author Woody
- * @date 2025/3/16
- */
-@Intercepts({
-        @Signature(type = StatementHandler.class, method = "getBoundSql", args = {}),
-        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
-        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
-        @Signature(
-                type = Executor.class, method = "query",
-                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
-        ),
-        @Signature(
-                type = Executor.class, method = "query",
-                args = {
-                        MappedStatement.class, Object.class, RowBounds.class,
-                        ResultHandler.class, CacheKey.class, BoundSql.class
-                }
-        )
-})
-public class CustomizeMybatisInterceptor extends MybatisPlusInterceptor {
-    private final boolean dynamicDatasource;
-    private final Map<String, String> schemas;
-
-    public CustomizeMybatisInterceptor(@NonNull ApplicationContext applicationContext) {
-        DataSource dataSource = applicationContext.getBean(DataSource.class);
-        if (this.dynamicDatasource = dataSource instanceof DynamicRoutingDataSource) {
-            DynamicDataSourceProperties properties = applicationContext.getBean(DynamicDataSourceProperties.class);
-            Map<String, DataSourceProperty> configs = properties.getDatasource();
-            this.schemas = Maps.newHashMapWithExpectedSize(configs.size());
-            configs.forEach((key, config) -> this.schemas.put(key, SQLUtils.getSchema(config.getUrl())));
-        } else {
-            this.schemas = Maps.newHashMapWithExpectedSize(1);
-            if (dataSource instanceof HikariDataSource) {
-                this.schemas.put(null, SQLUtils.getSchema(((HikariDataSource) dataSource).getJdbcUrl()));
-            } else {
-                throw new RuntimeException("Unknown datasource: " + dataSource);
-            }
-        }
-    }
-
-    /**
-     * 获取方法调用上下文
-     *
-     * @param invocation 调用信息
-     * @return 上下文实例
-     */
-    private Tables.Context getContext(Invocation invocation) {
-        Object[] args = invocation.getArgs();
-        String id = ((MappedStatement) args[0]).getId();
-        String namespace = id.substring(0, id.lastIndexOf('.'));
-        String schema = this.schemas.get(this.dynamicDatasource ? DynamicDataSourceContextHolder.peek() : null);
-        return new Tables.Context(schema, namespace);
-    }
-
-    @Override
-    public Object intercept(Invocation invocation) throws Throwable {
-        if (invocation.getTarget() instanceof Executor) {
-            Tables.setContext(this.getContext(invocation));
-            try {
-                return super.intercept(invocation);
-            } finally {
-                Tables.setContext(null);
-            }
-        }
-        return super.intercept(invocation);
-    }
-}

+ 75 - 0
framework-database/src/main/java/com/chelvc/framework/database/interceptor/CustomizeMybatisPlusInterceptor.java

@@ -0,0 +1,75 @@
+package com.chelvc.framework.database.interceptor;
+
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
+import com.chelvc.framework.base.context.ApplicationContextHolder;
+import lombok.NonNull;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.Invocation;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * 自定义MybatisPlus拦截器
+ *
+ * @author Woody
+ * @date 2025/3/16
+ */
+public abstract class CustomizeMybatisPlusInterceptor extends MybatisPlusInterceptor {
+    public CustomizeMybatisPlusInterceptor(@NonNull ApplicationContext applicationContext) {
+        // 设置自定义租户隔离拦截器
+        ApplicationContextHolder.getSortBeans(applicationContext, InnerInterceptor.class)
+                .forEach(this::addInnerInterceptor);
+
+        // 设置数据环境隔离过滤拦截器
+        this.addInnerInterceptor(new TenantLineInnerInterceptor() {
+            {
+                this.setTenantLineHandler(new EnvIsolateInterceptor());
+            }
+        });
+
+        // 设置数据逻辑删除过滤拦截器
+        this.addInnerInterceptor(new TenantLineInnerInterceptor() {
+            {
+                this.setTenantLineHandler(new DeletedIsolateInterceptor());
+            }
+        });
+
+        // 设置分页拦截器,数据过滤条件与拦截器设置顺序有关,分页拦截器最后设置才能在分页时同时使用数据隔离过滤条件
+        this.addInnerInterceptor(new PaginationInnerInterceptor());
+    }
+
+    /**
+     * 获取数据库Schema
+     *
+     * @return Schema名称
+     */
+    protected abstract String getSchema();
+
+    /**
+     * 获取方法调用上下文
+     *
+     * @param invocation 调用信息
+     * @return 上下文实例
+     */
+    protected Tables.Context getContext(Invocation invocation) {
+        Object[] args = invocation.getArgs();
+        String id = ((MappedStatement) args[0]).getId();
+        return new Tables.Context(id, this.getSchema());
+    }
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        if (invocation.getTarget() instanceof Executor) {
+            Tables.setContext(this.getContext(invocation));
+            try {
+                return super.intercept(invocation);
+            } finally {
+                Tables.setContext(null);
+            }
+        }
+        return super.intercept(invocation);
+    }
+}

+ 66 - 0
framework-database/src/main/java/com/chelvc/framework/database/interceptor/DynamicDataSourceMybatisPlusInterceptor.java

@@ -0,0 +1,66 @@
+package com.chelvc.framework.database.interceptor;
+
+import java.sql.Connection;
+import java.util.Map;
+
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import com.chelvc.framework.database.util.SQLUtils;
+import com.google.common.collect.Maps;
+import lombok.NonNull;
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+/**
+ * 动态数据源MybatisPlus拦截器
+ *
+ * @author Woody
+ * @date 2025/3/17
+ */
+@Component
+@Intercepts({
+        @Signature(type = StatementHandler.class, method = "getBoundSql", args = {}),
+        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
+        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
+        @Signature(
+                type = Executor.class, method = "query",
+                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
+        ),
+        @Signature(
+                type = Executor.class, method = "query",
+                args = {
+                        MappedStatement.class, Object.class, RowBounds.class,
+                        ResultHandler.class, CacheKey.class, BoundSql.class
+                }
+        )
+})
+@ConditionalOnClass(DynamicDataSourceAutoConfiguration.class)
+public class DynamicDataSourceMybatisPlusInterceptor extends CustomizeMybatisPlusInterceptor {
+    private final Map<String, String> schemas;
+
+    public DynamicDataSourceMybatisPlusInterceptor(@NonNull ApplicationContext applicationContext) {
+        super(applicationContext);
+
+        DynamicDataSourceProperties properties = applicationContext.getBean(DynamicDataSourceProperties.class);
+        Map<String, DataSourceProperty> sources = properties.getDatasource();
+        this.schemas = Maps.newHashMapWithExpectedSize(sources.size());
+        sources.forEach((key, source) -> this.schemas.put(key, SQLUtils.getSchema(source.getUrl())));
+    }
+
+    @Override
+    protected String getSchema() {
+        return this.schemas.get(DynamicDataSourceContextHolder.peek());
+    }
+}

+ 66 - 0
framework-database/src/main/java/com/chelvc/framework/database/interceptor/NormalDataSourceMybatisPlusInterceptor.java

@@ -0,0 +1,66 @@
+package com.chelvc.framework.database.interceptor;
+
+import java.sql.Connection;
+import javax.sql.DataSource;
+
+import com.chelvc.framework.database.util.SQLUtils;
+import com.zaxxer.hikari.HikariDataSource;
+import lombok.NonNull;
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+/**
+ * 普通数据源MybatisPlus拦截器
+ *
+ * @author Woody
+ * @date 2025/3/17
+ */
+@Component
+@Intercepts({
+        @Signature(type = StatementHandler.class, method = "getBoundSql", args = {}),
+        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
+        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
+        @Signature(
+                type = Executor.class, method = "query",
+                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
+        ),
+        @Signature(
+                type = Executor.class, method = "query",
+                args = {
+                        MappedStatement.class, Object.class, RowBounds.class,
+                        ResultHandler.class, CacheKey.class, BoundSql.class
+                }
+        )
+})
+@ConditionalOnMissingClass(
+        "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration"
+)
+public class NormalDataSourceMybatisPlusInterceptor extends CustomizeMybatisPlusInterceptor {
+    private final String schema;
+
+    public NormalDataSourceMybatisPlusInterceptor(@NonNull ApplicationContext applicationContext) {
+        super(applicationContext);
+
+        DataSource dataSource = applicationContext.getBean(DataSource.class);
+        if (dataSource instanceof HikariDataSource) {
+            this.schema = SQLUtils.getSchema(((HikariDataSource) dataSource).getJdbcUrl());
+        } else {
+            throw new RuntimeException("Unknown datasource: " + dataSource);
+        }
+    }
+
+    @Override
+    protected String getSchema() {
+        return this.schema;
+    }
+}

+ 8 - 7
framework-database/src/main/java/com/chelvc/framework/database/interceptor/Tables.java

@@ -51,18 +51,18 @@ final class Tables {
     @Getter
     static class Context implements Serializable {
         /**
-         * 数据库Schema
+         * 方法ID
          */
-        private final String schema;
+        private final String id;
 
         /**
-         * 命名空间
+         * 数据库Schema
          */
-        private final String namespace;
+        private final String schema;
 
-        public Context(@NonNull String schema, @NonNull String namespace) {
+        public Context(@NonNull String id, @NonNull String schema) {
+            this.id = id;
             this.schema = schema;
-            this.namespace = namespace;
         }
     }
 
@@ -232,7 +232,8 @@ final class Tables {
         if (table == null) {
             table = TABLE_NAME_MAPPING.computeIfAbsent(key, k -> {
                 boolean quoted = SQLUtils.isQuoted(name);
-                String namespace = ObjectUtils.ifNull(context, Context::getNamespace);
+                String id = ObjectUtils.ifNull(context, Context::getId);
+                String namespace = StringUtils.isEmpty(id) ? null : id.substring(0, id.lastIndexOf('.'));
                 for (TableInfo info : TableInfoHelper.getTableInfos()) {
                     String s = info.getCurrentNamespace(), n = getSimpleName(info.getTableName());
                     if ((Objects.equals(s, namespace) || StringUtils.isEmpty(namespace))