diff --git a/README.md b/README.md index daee01a..ed1624c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ | saas-datasource-spring-boot-starter | dynamic-datasource-spring-boot-starter | mybatis-plus-boot-starter | mybatis-spring-boot-starter | | :----: | :----: | :----: | :----: | +| 1.3.0 | version in (3.1.1, 3.4.1] | version <= 3.5.1 (latest) | version <= 2.2.2 (latest) | | 1.2.0 | version in (2.4.2, 3.1.1] | version <= 3.5.1 (latest) | version <= 2.2.2 (latest) | | 1.1.0 & 1.0.0 | version <= 2.4.2 |
根据`@SaaS`注解的位置分为两种情况:
1. 如果注解在Mapper上,则 version <= 3.0.7.1,若高于此版本dynamic-datasource会报错;
2. 如果注解不在Mapper上,则可使用目前最新版本 version <= 3.5.1 (latest)。
按[最佳实践](#最佳实践),推荐上述第二种情况,注解不要放在Mapper上。
| version <= 2.2.2 (latest) | @@ -50,7 +51,7 @@ com.air-software saas-datasource-spring-boot-starter - 1.2.0 + 1.3.0 ``` @@ -72,7 +73,6 @@ spring: url: jdbc:mysql://localhost/saas_common?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&autoReconnectForPools=true&allowMultiQueries=true username: root password: 123456 - driver-class-name: com.mysql.jdbc.Driver druid: filters: stat initial-size: 1 @@ -116,7 +116,6 @@ public class MySaaSDataSourceProvider implements SaaSDataSourceProvider { dataSourceProperty.setUrl(jdbcUrl); dataSourceProperty.setUsername(dataSourceConfig.getUsername()); dataSourceProperty.setPassword(dataSourceConfig.getPassword()); - dataSourceProperty.setDriverClassName(dataSourceConfig.getDriverClassName()); dataSourceProperty.setPoolName(dsKey); return saasDataSourceCreator.createDruidDataSource(dataSourceProperty); @@ -198,9 +197,16 @@ public class SaaSApplication { ## 更新日志 +### 1.3.0 + +- 更新并适配`dynamic-datasource-spring-boot-starter`至`3.4.1`版本; +- 更新并适配`spring-boot-starter-web`至`2.1.1.RELEASE`版本; +- 新增`SaaSDataSourceClassResolver`来解析注解标记的类,原因是`dynamic-datasource-spring-boot-starter`在`3.1.1`版本后删除了本工具之前使用的对应API,所以只能本工具自己再实现一个; +- 支持`SPI`,开发者可以省略`driverClassName`配置了。 + ### 1.2.0 -- 更新并适配`dynamic-datasource-spring-boot-starter`至3.1.1版本; +- 更新并适配`dynamic-datasource-spring-boot-starter`至`3.1.1`版本; - 优化了`SaaSDataSource`,底层改为使用`ArrayDeque`来实现栈; - 增加`SaaSDataSource.removeAll`方法,可强制移除所有数据源,包含DynamicDataSource上下文中的数据源。如果你不确定业务流程完成后是否还有残留数据,可在最后(比如拦截器的`afterCompletion`中)调用此方法来确保移除。 diff --git a/pom.xml b/pom.xml index 135f442..9007a89 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.air-software saas-datasource-spring-boot-starter - 1.2.0 + 1.3.0 jar saas-datasource-spring-boot-starter @@ -51,13 +51,13 @@ org.springframework.boot spring-boot-starter-web + 2.1.1.RELEASE provided - 2.0.5.RELEASE com.baomidou dynamic-datasource-spring-boot-starter - 3.1.1 + 3.4.1 com.alibaba diff --git a/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceAnnotationInterceptor.java b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceAnnotationInterceptor.java index f4767e8..9866cc0 100644 --- a/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceAnnotationInterceptor.java +++ b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceAnnotationInterceptor.java @@ -18,7 +18,6 @@ import com.airsoftware.saas.datasource.annotation.SaaS; import com.airsoftware.saas.datasource.context.SaaSDataSource; import com.airsoftware.saas.datasource.util.StringUtil; -import com.baomidou.dynamic.datasource.support.DataSourceClassResolver; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -43,7 +42,7 @@ public class SaaSDataSourceAnnotationInterceptor implements MethodInterceptor { @Setter private SaaSDataSourceManager manager; - private DataSourceClassResolver dataSourceClassResolver = new DataSourceClassResolver(); + private SaaSDataSourceClassResolver classResolver = new SaaSDataSourceClassResolver(); @Override public Object invoke(MethodInvocation invocation) throws Throwable { @@ -91,7 +90,7 @@ public Object invoke(MethodInvocation invocation) throws Throwable { */ private String getDsKeyField(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); - Class declaringClass = dataSourceClassResolver.targetClass(invocation); + Class declaringClass = classResolver.targetClass(invocation); SaaS saas = method.isAnnotationPresent(SaaS.class) ? method.getAnnotation(SaaS.class) : AnnotationUtils.findAnnotation(declaringClass, SaaS.class); Assert.notNull(saas, "Can not find @SaaS annotation, please ensure that you put the @SaaS annotation in right place."); diff --git a/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceClassResolver.java b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceClassResolver.java new file mode 100644 index 0000000..f92a49f --- /dev/null +++ b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceClassResolver.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018-2022 AIR Software. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.airsoftware.saas.datasource.core; + +import org.aopalliance.intercept.MethodInvocation; + +import java.lang.reflect.Field; +import java.lang.reflect.Proxy; + +/** + * 数据源类解析器 + * + * @author bit + */ +public class SaaSDataSourceClassResolver { + + private static boolean mpEnabled = false; + + private static Field mapperInterfaceField; + + static { + Class proxyClass = null; + try { + proxyClass = Class.forName("com.baomidou.mybatisplus.core.override.MybatisMapperProxy"); + } catch (ClassNotFoundException e1) { + try { + proxyClass = Class.forName("com.baomidou.mybatisplus.core.override.PageMapperProxy"); + } catch (ClassNotFoundException e2) { + try { + proxyClass = Class.forName("org.apache.ibatis.binding.MapperProxy"); + } catch (ClassNotFoundException ignored) { + } + } + } + if (proxyClass != null) { + try { + mapperInterfaceField = proxyClass.getDeclaredField("mapperInterface"); + mapperInterfaceField.setAccessible(true); + mpEnabled = true; + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + } + } + + public Class targetClass(MethodInvocation invocation) throws IllegalAccessException { + if (mpEnabled) { + Object target = invocation.getThis(); + Class targetClass = target.getClass(); + return Proxy.isProxyClass(targetClass) ? (Class) mapperInterfaceField.get(Proxy.getInvocationHandler(target)) : targetClass; + } + return invocation.getMethod().getDeclaringClass(); + } + +} diff --git a/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceCreator.java b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceCreator.java index e114e23..7e46947 100644 --- a/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceCreator.java +++ b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceCreator.java @@ -26,7 +26,6 @@ * * @author bit */ - public class SaaSDataSourceCreator { private DynamicDataSourceProperties properties; @@ -42,7 +41,7 @@ public SaaSDataSourceCreator(DynamicDataSourceProperties properties) { * @return 数据源 */ public DataSource createDruidDataSource(DataSourceProperty dataSourceProperty) { - DruidDataSourceCreator druidDataSourceCreator = new DruidDataSourceCreator(properties.getDruid()); + DruidDataSourceCreator druidDataSourceCreator = new DruidDataSourceCreator(properties); dataSourceProperty.setDruid(properties.getDruid()); return druidDataSourceCreator.createDataSource(dataSourceProperty); } diff --git a/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceManager.java b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceManager.java index 0c8997b..a628701 100644 --- a/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceManager.java +++ b/src/main/java/com/airsoftware/saas/datasource/core/SaaSDataSourceManager.java @@ -41,7 +41,7 @@ public class SaaSDataSourceManager { * @param dsKey */ public void addDataSource(String dsKey) { - Map dsMap = dynamicRoutingDataSource.getCurrentDataSources(); + Map dsMap = dynamicRoutingDataSource.getDataSources(); // 如果已被缓存则直接返回 if (dsMap != null && dsMap.containsKey(dsKey)) { return;