缓存改造:NotifyTemplate 使用 Redis 作为缓存

This commit is contained in:
YunaiV 2023-03-02 22:21:33 +08:00
parent 7ccdf86d3a
commit d23d72c8bb
9 changed files with 38 additions and 152 deletions

View File

@ -66,4 +66,12 @@ public interface RedisKeyConstants {
*/ */
String OAUTH_CLIENT = "oauth_client"; String OAUTH_CLIENT = "oauth_client";
/**
* 站内信模版的缓存
*
* KEY 格式notify_template::{code}
* VALUE 数据格式String 模版信息
*/
String NOTIFY_TEMPLATE = "notify_template";
} }

View File

@ -1,29 +0,0 @@
package cn.iocoder.yudao.module.system.mq.consumer.notify;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
import cn.iocoder.yudao.module.system.mq.message.notify.NotifyTemplateRefreshMessage;
import cn.iocoder.yudao.module.system.service.notify.NotifyTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 针对 {@link NotifyTemplateRefreshMessage} 的消费者
*
* @author xrcoder
*/
@Component
@Slf4j
public class NotifyTemplateRefreshConsumer extends AbstractChannelMessageListener<NotifyTemplateRefreshMessage> {
@Resource
private NotifyTemplateService notifyTemplateService;
@Override
public void onMessage(NotifyTemplateRefreshMessage message) {
log.info("[onMessage][收到 NotifyTemplate 刷新消息]");
notifyTemplateService.initLocalCache();
}
}

View File

@ -1,21 +0,0 @@
package cn.iocoder.yudao.module.system.mq.message.notify;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 站内信模板的数据刷新 Message
*
* @author xrcoder
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class NotifyTemplateRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {
return "system.notify-template.refresh";
}
}

View File

@ -1,33 +0,0 @@
package cn.iocoder.yudao.module.system.mq.producer.notify;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import cn.iocoder.yudao.module.system.mq.message.notify.NotifyTemplateRefreshMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Notify 站内信相关消息的 Producer
*
* @author xrcoder
* @since 2022-08-06
*/
@Slf4j
@Component
public class NotifyProducer {
@Resource
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link NotifyTemplateRefreshMessage} 消息
*/
public void sendNotifyTemplateRefreshMessage() {
NotifyTemplateRefreshMessage message = new NotifyTemplateRefreshMessage();
redisMQTemplate.send(message);
}
}

View File

@ -16,19 +16,6 @@ import java.util.Map;
*/ */
public interface NotifyTemplateService { public interface NotifyTemplateService {
/**
* 初始化站内信模板的本地缓存
*/
void initLocalCache();
/**
* 获得站内信模板从缓存中
*
* @param code 模板编码
* @return 站内信模板
*/
NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code);
/** /**
* 创建站内信模版 * 创建站内信模版
* *
@ -59,6 +46,14 @@ public interface NotifyTemplateService {
*/ */
NotifyTemplateDO getNotifyTemplate(Long id); NotifyTemplateDO getNotifyTemplate(Long id);
/**
* 获得站内信模板从缓存中
*
* @param code 模板编码
* @return 站内信模板
*/
NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code);
/** /**
* 获得站内信模版分页 * 获得站内信模版分页
* *

View File

@ -3,27 +3,28 @@ package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert; import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper; import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer; import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
/** /**
* 站内信模版 Service 实现类 * 站内信模版 Service 实现类
@ -43,36 +44,6 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
@Resource @Resource
private NotifyTemplateMapper notifyTemplateMapper; private NotifyTemplateMapper notifyTemplateMapper;
@Resource
private NotifyProducer notifyProducer;
/**
* 站内信模板缓存
* key站内信模板编码 {@link NotifyTemplateDO#getCode()}
* <p>
* 这里声明 volatile 修饰的原因是每次刷新时直接修改指向
*/
private volatile Map<String, NotifyTemplateDO> notifyTemplateCache;
/**
* 初始化站内信模板的本地缓存
*/
@Override
@PostConstruct
public void initLocalCache() {
// 第一步查询数据
List<NotifyTemplateDO> templates = notifyTemplateMapper.selectList();
log.info("[initLocalCache][缓存站内信模版,数量为:{}]", templates.size());
// 第二步构建缓存
notifyTemplateCache = CollectionUtils.convertMap(templates, NotifyTemplateDO::getCode);
}
@Override
public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) {
return notifyTemplateCache.get(code);
}
@Override @Override
public Long createNotifyTemplate(NotifyTemplateCreateReqVO createReqVO) { public Long createNotifyTemplate(NotifyTemplateCreateReqVO createReqVO) {
// 校验站内信编码是否重复 // 校验站内信编码是否重复
@ -82,13 +53,12 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
NotifyTemplateDO notifyTemplate = NotifyTemplateConvert.INSTANCE.convert(createReqVO); NotifyTemplateDO notifyTemplate = NotifyTemplateConvert.INSTANCE.convert(createReqVO);
notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent())); notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent()));
notifyTemplateMapper.insert(notifyTemplate); notifyTemplateMapper.insert(notifyTemplate);
// 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage();
return notifyTemplate.getId(); return notifyTemplate.getId();
} }
@Override @Override
@CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE,
allEntries = true) // allEntries 清空所有缓存因为可能修改到 code 字段不好清理
public void updateNotifyTemplate(NotifyTemplateUpdateReqVO updateReqVO) { public void updateNotifyTemplate(NotifyTemplateUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
validateNotifyTemplateExists(updateReqVO.getId()); validateNotifyTemplateExists(updateReqVO.getId());
@ -99,9 +69,6 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
NotifyTemplateDO updateObj = NotifyTemplateConvert.INSTANCE.convert(updateReqVO); NotifyTemplateDO updateObj = NotifyTemplateConvert.INSTANCE.convert(updateReqVO);
updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
notifyTemplateMapper.updateById(updateObj); notifyTemplateMapper.updateById(updateObj);
// 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage();
} }
@VisibleForTesting @VisibleForTesting
@ -110,13 +77,13 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
} }
@Override @Override
@CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE,
allEntries = true) // allEntries 清空所有缓存因为 id 不是直接的缓存 code不好清理
public void deleteNotifyTemplate(Long id) { public void deleteNotifyTemplate(Long id) {
// 校验存在 // 校验存在
validateNotifyTemplateExists(id); validateNotifyTemplateExists(id);
// 删除 // 删除
notifyTemplateMapper.deleteById(id); notifyTemplateMapper.deleteById(id);
// 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage();
} }
private void validateNotifyTemplateExists(Long id) { private void validateNotifyTemplateExists(Long id) {
@ -130,13 +97,20 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
return notifyTemplateMapper.selectById(id); return notifyTemplateMapper.selectById(id);
} }
@Override
@Cacheable(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, key = "#code",
unless = "#result == null")
public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) {
return notifyTemplateMapper.selectByCode(code);
}
@Override @Override
public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) { public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) {
return notifyTemplateMapper.selectPage(pageReqVO); return notifyTemplateMapper.selectPage(pageReqVO);
} }
@VisibleForTesting @VisibleForTesting
public void validateNotifyTemplateCodeDuplicate(Long id, String code) { void validateNotifyTemplateCodeDuplicate(Long id, String code) {
NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code); NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code);
if (template == null) { if (template == null) {
return; return;

View File

@ -100,7 +100,8 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
} }
@Override @Override
@Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientId") @Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientId",
unless = "#result == null")
public OAuth2ClientDO getOAuth2ClientFromCache(String clientId) { public OAuth2ClientDO getOAuth2ClientFromCache(String clientId) {
return oauth2ClientMapper.selectByClientId(clientId); return oauth2ClientMapper.selectByClientId(clientId);
} }

View File

@ -171,7 +171,8 @@ public class RoleServiceImpl implements RoleService {
} }
@Override @Override
@Cacheable(value = RedisKeyConstants.ROLE, key = "#id", unless = "#result == null") @Cacheable(value = RedisKeyConstants.ROLE, key = "#id",
unless = "#result == null")
public RoleDO getRoleFromCache(Long id) { public RoleDO getRoleFromCache(Long id) {
return roleMapper.selectById(id); return roleMapper.selectById(id);
} }

View File

@ -8,9 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.Notify
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper; import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -25,7 +23,6 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.verify;
/** /**
* {@link NotifyTemplateServiceImpl} 的单元测试类 * {@link NotifyTemplateServiceImpl} 的单元测试类
@ -41,9 +38,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
@Resource @Resource
private NotifyTemplateMapper notifyTemplateMapper; private NotifyTemplateMapper notifyTemplateMapper;
@MockBean
private NotifyProducer notifyProducer;
@Test @Test
public void testCreateNotifyTemplate_success() { public void testCreateNotifyTemplate_success() {
// 准备参数 // 准备参数
@ -57,7 +51,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
// 校验记录的属性是否正确 // 校验记录的属性是否正确
NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId); NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId);
assertPojoEquals(reqVO, notifyTemplate); assertPojoEquals(reqVO, notifyTemplate);
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
} }
@Test @Test
@ -76,7 +69,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
// 校验是否更新正确 // 校验是否更新正确
NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(reqVO.getId()); // 获取最新的 NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, notifyTemplate); assertPojoEquals(reqVO, notifyTemplate);
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
} }
@Test @Test
@ -100,7 +92,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
notifyTemplateService.deleteNotifyTemplate(id); notifyTemplateService.deleteNotifyTemplate(id);
// 校验数据不存在了 // 校验数据不存在了
assertNull(notifyTemplateMapper.selectById(id)); assertNull(notifyTemplateMapper.selectById(id));
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
} }
@Test @Test
@ -164,7 +155,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
// mock 数据 // mock 数据
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class); NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
notifyTemplateMapper.insert(dbNotifyTemplate); notifyTemplateMapper.insert(dbNotifyTemplate);
notifyTemplateService.initLocalCache();
// 准备参数 // 准备参数
String code = dbNotifyTemplate.getCode(); String code = dbNotifyTemplate.getCode();