Преглед на файлове

更新动态数据源路由逻辑

woody преди 1 година
родител
ревизия
738cee770a

+ 143 - 56
framework-database/src/main/java/com/chelvc/framework/database/interceptor/DynamicDatasourceInterceptor.java

@@ -14,6 +14,11 @@ import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
 import org.springframework.aop.framework.AopProxyUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.Order;
@@ -26,80 +31,162 @@ import org.springframework.util.CollectionUtils;
  * @date 2024/1/30
  */
 @Slf4j
-@Aspect
-@Order(Ordered.HIGHEST_PRECEDENCE)
 @ConditionalOnClass(DynamicDataSourceContextHolder.class)
-public class DynamicDatasourceInterceptor {
-    private final Map<String, String> datasourceContext;
+public class DynamicDatasourceInterceptor implements BeanDefinitionRegistryPostProcessor {
+    /**
+     * 判断是否是兼容模式
+     *
+     * @return true/false
+     */
+    private boolean isCompatible() {
+        try {
+            // 尝试加载@DubboService注解
+            this.getClass().getClassLoader().loadClass("org.apache.dubbo.config.annotation.DubboService");
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+    }
 
-    public DynamicDatasourceInterceptor(@NonNull DynamicDataSourceProperties properties) {
-        // 初始化数据源标识集合
-        Set<String> keys = properties.getDatasource().keySet();
-        if (CollectionUtils.isEmpty(keys)) {
-            this.datasourceContext = Collections.emptyMap();
+    @Override
+    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+        if (this.isCompatible()) {
+            registry.registerBeanDefinition("compatibleDynamicDatasourceRouter",
+                    new RootBeanDefinition(CompatibleDynamicDatasourceRouter.class));
         } else {
-            this.datasourceContext = Maps.newHashMapWithExpectedSize(keys.size());
-            keys.forEach(value -> {
-                for (String key : StringUtils.splitActives(value)) {
-                    this.datasourceContext.put(key, value);
-                }
-            });
+            registry.registerBeanDefinition("standardDynamicDatasourceRouter",
+                    new RootBeanDefinition(StandardDynamicDatasourceRouter.class));
         }
-        log.debug("Initialized datasource context: {}", this.datasourceContext);
     }
 
     /**
-     * 查找数据源标识
-     *
-     * @param point 方法拦截点
-     * @return 数据源标识
+     * 动态数据源路由器抽象实现
      */
-    private String lookupDatasourceKey(ProceedingJoinPoint point) {
-        Object target = point.getTarget();
+    public static abstract class AbstractDynamicDatasourceRouter {
+        private final Map<String, String> datasourceContext;
 
-        // 根据目标类对象查找数据源标识
-        String className = AopProxyUtils.ultimateTargetClass(target).getName();
-        Set<Map.Entry<String, String>> routes = this.datasourceContext.entrySet();
-        String key = routes.stream().filter(entry -> className.startsWith(entry.getKey())).findAny()
-                .map(Map.Entry::getValue).orElse(null);
-        if (StringUtils.notEmpty(key)) {
-            return key;
+        public AbstractDynamicDatasourceRouter(@NonNull DynamicDataSourceProperties properties) {
+            // 初始化数据源标识集合
+            Set<String> keys = properties.getDatasource().keySet();
+            if (CollectionUtils.isEmpty(keys)) {
+                this.datasourceContext = Collections.emptyMap();
+            } else {
+                this.datasourceContext = Maps.newHashMapWithExpectedSize(keys.size());
+                keys.forEach(value -> {
+                    for (String key : StringUtils.splitActives(value)) {
+                        this.datasourceContext.put(key, value);
+                    }
+                });
+            }
+            log.debug("Initialized datasource context: {}", this.datasourceContext);
         }
 
-        // 根据目标接口对象查找数据源标识
-        Class<?>[] interfaces = AopProxyUtils.proxiedUserInterfaces(target);
-        if (interfaces.length > 0) {
-            for (Class<?> clazz : interfaces) {
-                String interfaceName = clazz.getName();
-                String route = routes.stream().filter(entry -> interfaceName.startsWith(entry.getKey())).findAny()
-                        .map(Map.Entry::getValue).orElse(null);
-                if (StringUtils.notEmpty(route)) {
-                    return route;
+        /**
+         * 查找数据源标识
+         *
+         * @param point 方法拦截点
+         * @return 数据源标识
+         */
+        private String lookupDatasourceKey(ProceedingJoinPoint point) {
+            Object target = point.getTarget();
+
+            // 根据目标类对象查找数据源标识
+            String className = AopProxyUtils.ultimateTargetClass(target).getName();
+            Set<Map.Entry<String, String>> routes = this.datasourceContext.entrySet();
+            String key = routes.stream().filter(entry -> className.startsWith(entry.getKey())).findAny()
+                    .map(Map.Entry::getValue).orElse(null);
+            if (StringUtils.notEmpty(key)) {
+                return key;
+            }
+
+            // 根据目标接口对象查找数据源标识
+            Class<?>[] interfaces = AopProxyUtils.proxiedUserInterfaces(target);
+            if (interfaces.length > 0) {
+                for (Class<?> clazz : interfaces) {
+                    String interfaceName = clazz.getName();
+                    String route = routes.stream().filter(entry -> interfaceName.startsWith(entry.getKey())).findAny()
+                            .map(Map.Entry::getValue).orElse(null);
+                    if (StringUtils.notEmpty(route)) {
+                        return route;
+                    }
                 }
             }
+            return null;
+        }
+
+        /**
+         * 数据源路由
+         *
+         * @param point 方法拦截点
+         * @return 方法调用结果
+         * @throws Throwable 方法调用异常
+         */
+        protected Object routing(ProceedingJoinPoint point) throws Throwable {
+            String key = this.lookupDatasourceKey(point);
+            log.debug("Initializing datasource context for {}: {}", point.getSignature().toShortString(), key);
+            DynamicDataSourceContextHolder.push(key);
+            try {
+                return point.proceed(point.getArgs());
+            } finally {
+                DynamicDataSourceContextHolder.poll();
+            }
         }
-        return null;
     }
 
     /**
-     * 数据源路由
-     *
-     * @param point 方法拦截点
-     * @return 方法调用结果
-     * @throws Throwable 方法调用异常
+     * 动态数据源拦截器标准实现
      */
-    @Around("@within(org.apache.ibatis.annotations.Mapper) " +
-            "|| this(com.baomidou.mybatisplus.core.mapper.BaseMapper) " +
-            "|| this(com.chelvc.framework.database.support.EnhanceMapper)"
-    )
-    public Object routing(ProceedingJoinPoint point) throws Throwable {
-        String key = this.lookupDatasourceKey(point);
-        log.debug("Initializing datasource context for {}: {}", point.getSignature().toShortString(), key);
-        DynamicDataSourceContextHolder.push(key);
-        try {
-            return point.proceed(point.getArgs());
-        } finally {
-            DynamicDataSourceContextHolder.poll();
+    @Aspect
+    @Order(Ordered.HIGHEST_PRECEDENCE)
+    public static class StandardDynamicDatasourceRouter extends AbstractDynamicDatasourceRouter {
+        public StandardDynamicDatasourceRouter(DynamicDataSourceProperties properties) {
+            super(properties);
+        }
+
+        /**
+         * 数据源路由
+         *
+         * @param point 方法拦截点
+         * @return 方法调用结果
+         * @throws Throwable 方法调用异常
+         */
+        @Around("@within(org.springframework.stereotype.Service) " +
+                "|| @within(org.apache.ibatis.annotations.Mapper) " +
+                "|| this(com.baomidou.mybatisplus.core.mapper.BaseMapper) " +
+                "|| this(com.chelvc.framework.database.support.EnhanceMapper)")
+        public Object routing(ProceedingJoinPoint point) throws Throwable {
+            return super.routing(point);
+        }
+    }
+
+    /**
+     * 动态数据源拦截器兼容实现
+     */
+    @Aspect
+    @Order(Ordered.HIGHEST_PRECEDENCE)
+    public static class CompatibleDynamicDatasourceRouter extends AbstractDynamicDatasourceRouter {
+        public CompatibleDynamicDatasourceRouter(DynamicDataSourceProperties properties) {
+            super(properties);
+        }
+
+        /**
+         * 数据源路由
+         *
+         * @param point 方法拦截点
+         * @return 方法调用结果
+         * @throws Throwable 方法调用异常
+         */
+        @Around("@within(org.springframework.stereotype.Service) " +
+                "|| @within(org.apache.ibatis.annotations.Mapper) " +
+                "|| @within(org.apache.dubbo.config.annotation.DubboService) " +
+                "|| this(com.baomidou.mybatisplus.core.mapper.BaseMapper) " +
+                "|| this(com.chelvc.framework.database.support.EnhanceMapper)")
+        public Object routing(ProceedingJoinPoint point) throws Throwable {
+            return super.routing(point);
         }
     }
 }

+ 4 - 4
framework-dependencies/pom.xml

@@ -10,8 +10,8 @@
     <packaging>pom</packaging>
 
     <properties>
-        <maven.compiler.source>1.8</maven.compiler.source>
-        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source.version>1.8</maven.compiler.source.version>
+        <maven.compiler.target.version>1.8</maven.compiler.target.version>
         <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
         <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
         <maven-source-plugin.version>3.2.1</maven-source-plugin.version>
@@ -276,8 +276,8 @@
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>${maven-compiler-plugin.version}</version>
                 <configuration>
-                    <source>${maven.compiler.source}</source>
-                    <target>${maven.compiler.target}</target>
+                    <source>${maven.compiler.source.version}</source>
+                    <target>${maven.compiler.target.version}</target>
                     <compilerArgs>
                         <compilerArg>-parameters</compilerArg>
                     </compilerArgs>