Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
e20600f0
提交
e20600f0
authored
6月 17, 2022
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
基于 Guava 实现 tenant 租户数据的本地缓存
上级
31c24cd3
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
10 行增加
和
215 行删除
+10
-215
TenantFrameworkServiceImpl.java
...ework/tenant/core/service/TenantFrameworkServiceImpl.java
+3
-2
TenantRefreshConsumer.java
...dule/system/mq/consumer/tenant/TenantRefreshConsumer.java
+0
-29
TenantRefreshMessage.java
...module/system/mq/message/tenant/TenantRefreshMessage.java
+0
-21
TenantProducer.java
...udao/module/system/mq/producer/tenant/TenantProducer.java
+0
-29
TenantService.java
...der/yudao/module/system/service/tenant/TenantService.java
+0
-5
TenantServiceImpl.java
...yudao/module/system/service/tenant/TenantServiceImpl.java
+6
-92
TenantServiceImplTest.java
...o/module/system/service/tenant/TenantServiceImplTest.java
+1
-37
没有找到文件。
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java
浏览文件 @
e20600f0
...
...
@@ -52,14 +52,15 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
});
@Override
@SneakyThrows
public
List
<
Long
>
getTenantIds
()
{
return
getTenantIdsCache
.
get
Unchecked
(
Boolean
.
TRUE
);
return
getTenantIdsCache
.
get
(
Boolean
.
TRUE
);
}
@Override
@SneakyThrows
public
void
validTenant
(
Long
id
)
{
validTenantCache
.
get
Unchecked
(
id
).
checkError
();
validTenantCache
.
get
(
id
).
checkError
();
}
}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java
deleted
100644 → 0
浏览文件 @
31c24cd3
package
cn
.
iocoder
.
yudao
.
module
.
system
.
mq
.
consumer
.
tenant
;
import
cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener
;
import
cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage
;
import
cn.iocoder.yudao.module.system.service.tenant.TenantService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Component
;
import
javax.annotation.Resource
;
/**
* 针对 {@link cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage} 的消费者
*
* @author 芋道源码
*/
@Component
@Slf4j
public
class
TenantRefreshConsumer
extends
AbstractChannelMessageListener
<
TenantRefreshMessage
>
{
@Resource
private
TenantService
tenantService
;
@Override
public
void
onMessage
(
TenantRefreshMessage
message
)
{
log
.
info
(
"[onMessage][收到 Tenant 刷新消息]"
);
tenantService
.
initLocalCache
();
}
}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java
deleted
100644 → 0
浏览文件 @
31c24cd3
package
cn
.
iocoder
.
yudao
.
module
.
system
.
mq
.
message
.
tenant
;
import
cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
/**
* 租户数据刷新 Message
*
* @author 芋道源码
*/
@Data
@EqualsAndHashCode
(
callSuper
=
true
)
public
class
TenantRefreshMessage
extends
AbstractChannelMessage
{
@Override
public
String
getChannel
()
{
return
"system.tenant.refresh"
;
}
}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java
deleted
100644 → 0
浏览文件 @
31c24cd3
package
cn
.
iocoder
.
yudao
.
module
.
system
.
mq
.
producer
.
tenant
;
import
cn.iocoder.yudao.framework.mq.core.RedisMQTemplate
;
import
cn.iocoder.yudao.module.system.mq.message.permission.RoleRefreshMessage
;
import
cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage
;
import
org.springframework.stereotype.Component
;
import
javax.annotation.Resource
;
/**
* Tenant 租户相关消息的 Producer
*
* @author 芋道源码
*/
@Component
public
class
TenantProducer
{
@Resource
private
RedisMQTemplate
redisMQTemplate
;
/**
* 发送 {@link RoleRefreshMessage} 消息
*/
public
void
sendTenantRefreshMessage
()
{
TenantRefreshMessage
message
=
new
TenantRefreshMessage
();
redisMQTemplate
.
send
(
message
);
}
}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java
浏览文件 @
e20600f0
...
...
@@ -22,11 +22,6 @@ import java.util.Set;
*/
public
interface
TenantService
{
/**
* 初始化租户的本地缓存
*/
void
initLocalCache
();
/**
* 创建租户
*
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
浏览文件 @
e20600f0
...
...
@@ -23,31 +23,25 @@ import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
import
cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper
;
import
cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum
;
import
cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum
;
import
cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer
;
import
cn.iocoder.yudao.module.system.service.permission.MenuService
;
import
cn.iocoder.yudao.module.system.service.permission.PermissionService
;
import
cn.iocoder.yudao.module.system.service.permission.RoleService
;
import
cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler
;
import
cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler
;
import
cn.iocoder.yudao.module.system.service.user.AdminUserService
;
import
lombok.Getter
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.transaction.support.TransactionSynchronization
;
import
org.springframework.transaction.support.TransactionSynchronizationManager
;
import
org.springframework.validation.annotation.Validated
;
import
javax.annotation.PostConstruct
;
import
javax.annotation.Resource
;
import
java.util.*
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Set
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
exception
.
util
.
ServiceExceptionUtil
.
exception
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
collection
.
CollectionUtils
.
convertImmutableMap
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
collection
.
CollectionUtils
.
getMaxValue
;
import
static
cn
.
iocoder
.
yudao
.
module
.
system
.
enums
.
ErrorCodeConstants
.*;
import
static
java
.
util
.
Collections
.
singleton
;
...
...
@@ -61,26 +55,6 @@ import static java.util.Collections.singleton;
@Slf4j
public
class
TenantServiceImpl
implements
TenantService
{
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
*/
private
static
final
long
SCHEDULER_PERIOD
=
5
*
60
*
1000L
;
/**
* 角色缓存
* key:角色编号 {@link RoleDO#getId()}
*
* 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
*/
@Getter
private
volatile
Map
<
Long
,
TenantDO
>
tenantCache
;
/**
* 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新
*/
@Getter
private
volatile
Date
maxUpdateTime
;
@SuppressWarnings
(
"SpringJavaAutowiredFieldsWarningInspection"
)
@Autowired
(
required
=
false
)
// 由于 yudao.tenant.enable 配置项,可以关闭多租户的功能,所以这里只能不强制注入
private
TenantProperties
tenantProperties
;
...
...
@@ -100,61 +74,15 @@ public class TenantServiceImpl implements TenantService {
@Resource
private
PermissionService
permissionService
;
@Resource
private
TenantProducer
tenantProducer
;
/**
* 初始化 {@link #tenantCache} 缓存
*/
@Override
@PostConstruct
public
void
initLocalCache
()
{
// 获取租户列表,如果有更新
List
<
TenantDO
>
tenantList
=
loadTenantIfUpdate
(
maxUpdateTime
);
if
(
CollUtil
.
isEmpty
(
tenantList
))
{
return
;
}
// 写入缓存
tenantCache
=
convertImmutableMap
(
tenantList
,
TenantDO:
:
getId
);
maxUpdateTime
=
getMaxValue
(
tenantList
,
TenantDO:
:
getUpdateTime
);
log
.
info
(
"[initLocalCache][初始化 Tenant 数量为 {}]"
,
tenantList
.
size
());
}
@Scheduled
(
fixedDelay
=
SCHEDULER_PERIOD
,
initialDelay
=
SCHEDULER_PERIOD
)
public
void
schedulePeriodicRefresh
()
{
initLocalCache
();
}
/**
* 如果租户发生变化,从数据库中获取最新的全量租户。
* 如果未发生变化,则返回空
*
* @param maxUpdateTime 当前租户的最大更新时间
* @return 租户列表
*/
private
List
<
TenantDO
>
loadTenantIfUpdate
(
Date
maxUpdateTime
)
{
// 第一步,判断是否要更新。
if
(
maxUpdateTime
==
null
)
{
// 如果更新时间为空,说明 DB 一定有新数据
log
.
info
(
"[loadTenantIfUpdate][首次加载全量租户]"
);
}
else
{
// 判断数据库中是否有更新的租户
if
(
tenantMapper
.
selectCountByUpdateTimeGt
(
maxUpdateTime
)
==
0
)
{
return
null
;
}
log
.
info
(
"[loadTenantIfUpdate][增量加载全量租户]"
);
}
// 第二步,如果有更新,则从数据库加载所有租户
return
tenantMapper
.
selectList
();
}
@Override
public
List
<
Long
>
getTenantIds
()
{
return
new
ArrayList
<>(
tenantCache
.
keySet
());
List
<
TenantDO
>
tenants
=
tenantMapper
.
selectList
();
return
CollectionUtils
.
convertList
(
tenants
,
TenantDO:
:
getId
);
}
@Override
public
void
validTenant
(
Long
id
)
{
TenantDO
tenant
=
tenantCache
.
ge
t
(
id
);
TenantDO
tenant
=
getTenan
t
(
id
);
if
(
tenant
==
null
)
{
throw
exception
(
TENANT_NOT_EXISTS
);
}
...
...
@@ -184,13 +112,6 @@ public class TenantServiceImpl implements TenantService {
// 修改租户的管理员
tenantMapper
.
updateById
(
new
TenantDO
().
setId
(
tenant
.
getId
()).
setContactUserId
(
userId
));
});
// 发送刷新消息
TransactionSynchronizationManager
.
registerSynchronization
(
new
TransactionSynchronization
()
{
@Override
public
void
afterCommit
()
{
tenantProducer
.
sendTenantRefreshMessage
();
}
});
return
tenant
.
getId
();
}
...
...
@@ -228,13 +149,6 @@ public class TenantServiceImpl implements TenantService {
if
(
ObjectUtil
.
notEqual
(
tenant
.
getPackageId
(),
updateReqVO
.
getPackageId
()))
{
updateTenantRoleMenu
(
tenant
.
getId
(),
tenantPackage
.
getMenuIds
());
}
// 发送刷新消息
TransactionSynchronizationManager
.
registerSynchronization
(
new
TransactionSynchronization
()
{
@Override
public
void
afterCommit
()
{
tenantProducer
.
sendTenantRefreshMessage
();
}
});
}
@Override
...
...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
浏览文件 @
e20600f0
package
cn
.
iocoder
.
yudao
.
module
.
system
.
service
.
tenant
;
import
cn.hutool.core.util.ReflectUtil
;
import
cn.iocoder.yudao.framework.common.enums.CommonStatusEnum
;
import
cn.iocoder.yudao.framework.common.pojo.PageResult
;
import
cn.iocoder.yudao.framework.tenant.config.TenantProperties
;
import
cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder
;
import
cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest
;
import
cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantCreateReqVO
;
import
cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExportReqVO
;
import
cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO
;
...
...
@@ -16,14 +16,12 @@ import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
import
cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper
;
import
cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum
;
import
cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum
;
import
cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer
;
import
cn.iocoder.yudao.module.system.service.permission.MenuService
;
import
cn.iocoder.yudao.module.system.service.permission.PermissionService
;
import
cn.iocoder.yudao.module.system.service.permission.RoleService
;
import
cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler
;
import
cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler
;
import
cn.iocoder.yudao.module.system.service.user.AdminUserService
;
import
cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.boot.test.mock.mockito.MockBean
;
...
...
@@ -34,13 +32,11 @@ import java.time.Duration;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
collection
.
SetUtils
.
asSet
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
date
.
DateUtils
.
addTime
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
date
.
DateUtils
.
buildTime
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
object
.
ObjectUtils
.
cloneIgnoreId
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
object
.
ObjectUtils
.
max
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
test
.
core
.
util
.
AssertUtils
.
assertPojoEquals
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
test
.
core
.
util
.
AssertUtils
.
assertServiceException
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
test
.
core
.
util
.
RandomUtils
.*;
...
...
@@ -78,43 +74,18 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
private
MenuService
menuService
;
@MockBean
private
PermissionService
permissionService
;
@MockBean
private
TenantProducer
tenantProducer
;
@BeforeEach
public
void
setUp
()
{
// 清理缓存
ReflectUtil
.
setFieldValue
(
tenantService
,
"tenantCache"
,
Collections
.
emptyMap
());
ReflectUtil
.
setFieldValue
(
tenantService
,
"maxUpdateTime"
,
null
);
// 清理租户上下文
TenantContextHolder
.
clear
();
}
@Test
public
void
testInitLocalCache
()
{
// mock 数据
TenantDO
tenantDO1
=
randomPojo
(
TenantDO
.
class
);
tenantMapper
.
insert
(
tenantDO1
);
TenantDO
tenantDO2
=
randomPojo
(
TenantDO
.
class
);
tenantMapper
.
insert
(
tenantDO2
);
// 调用
tenantService
.
initLocalCache
();
// 断言 tenantCache 缓存
Map
<
Long
,
TenantDO
>
tenantCache
=
tenantService
.
getTenantCache
();
assertEquals
(
2
,
tenantCache
.
size
());
assertPojoEquals
(
tenantDO1
,
tenantCache
.
get
(
tenantDO1
.
getId
()));
assertPojoEquals
(
tenantDO2
,
tenantCache
.
get
(
tenantDO2
.
getId
()));
// 断言 maxUpdateTime 缓存
assertEquals
(
max
(
tenantDO1
.
getUpdateTime
(),
tenantDO2
.
getUpdateTime
()),
tenantService
.
getMaxUpdateTime
());
}
@Test
public
void
testGetTenantIds
()
{
// mock 数据
TenantDO
tenant
=
randomPojo
(
TenantDO
.
class
,
o
->
o
.
setId
(
1L
));
tenantMapper
.
insert
(
tenant
);
tenantService
.
initLocalCache
();
// 调用,并断言业务异常
List
<
Long
>
result
=
tenantService
.
getTenantIds
();
...
...
@@ -131,7 +102,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
// mock 数据
TenantDO
tenant
=
randomPojo
(
TenantDO
.
class
,
o
->
o
.
setId
(
1L
).
setStatus
(
CommonStatusEnum
.
DISABLE
.
getStatus
()));
tenantMapper
.
insert
(
tenant
);
tenantService
.
initLocalCache
();
// 调用,并断言业务异常
assertServiceException
(()
->
tenantService
.
validTenant
(
1L
),
TENANT_DISABLE
,
tenant
.
getName
());
...
...
@@ -143,7 +113,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
TenantDO
tenant
=
randomPojo
(
TenantDO
.
class
,
o
->
o
.
setId
(
1L
).
setStatus
(
CommonStatusEnum
.
ENABLE
.
getStatus
())
.
setExpireTime
(
buildTime
(
2020
,
2
,
2
)));
tenantMapper
.
insert
(
tenant
);
tenantService
.
initLocalCache
();
// 调用,并断言业务异常
assertServiceException
(()
->
tenantService
.
validTenant
(
1L
),
TENANT_EXPIRE
,
tenant
.
getName
());
...
...
@@ -155,7 +124,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
TenantDO
tenant
=
randomPojo
(
TenantDO
.
class
,
o
->
o
.
setId
(
1L
).
setStatus
(
CommonStatusEnum
.
ENABLE
.
getStatus
())
.
setExpireTime
(
addTime
(
Duration
.
ofDays
(
1
))));
tenantMapper
.
insert
(
tenant
);
tenantService
.
initLocalCache
();
// 调用,并断言业务异常
tenantService
.
validTenant
(
1L
);
...
...
@@ -206,8 +174,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
verify
(
permissionService
).
assignRoleMenu
(
eq
(
200L
),
same
(
tenantPackage
.
getMenuIds
()));
// verify 分配角色
verify
(
permissionService
).
assignUserRole
(
eq
(
300L
),
eq
(
singleton
(
200L
)));
// verify 发送刷新消息
verify
(
tenantProducer
).
sendTenantRefreshMessage
();
}
@Test
...
...
@@ -240,8 +206,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
// 校验是否更新正确
TenantDO
tenant
=
tenantMapper
.
selectById
(
reqVO
.
getId
());
// 获取最新的
assertPojoEquals
(
reqVO
,
tenant
);
// verify 发送刷新消息
verify
(
tenantProducer
).
sendTenantRefreshMessage
();
// verify 设置角色权限
verify
(
permissionService
).
assignRoleMenu
(
eq
(
100L
),
eq
(
asSet
(
200L
,
201L
)));
verify
(
permissionService
).
assignRoleMenu
(
eq
(
101L
),
eq
(
asSet
(
201L
)));
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论