All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.houkunlin.system.dict.starter.DictRegistrar Maven / Gradle / Ivy
package com.houkunlin.system.dict.starter;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.houkunlin.system.dict.starter.bean.DictTypeVo;
import com.houkunlin.system.dict.starter.bean.DictValueVo;
import com.houkunlin.system.dict.starter.notice.RefreshDictEvent;
import com.houkunlin.system.dict.starter.notice.RefreshDictTypeEvent;
import com.houkunlin.system.dict.starter.notice.RefreshDictValueEvent;
import com.houkunlin.system.dict.starter.properties.DictProperties;
import com.houkunlin.system.dict.starter.provider.DictProvider;
import com.houkunlin.system.dict.starter.provider.SystemDictProvider;
import com.houkunlin.system.dict.starter.store.DictStore;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.Async;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* 字典注册,把字典发送到缓存中
*
* @author HouKunLin
*/
@Data
@Configuration
@RequiredArgsConstructor
public class DictRegistrar implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(DictRegistrar.class);
private final List providers;
private final DictStore store;
private final DictProperties properties;
/**
* 上一次刷新字典时间
*/
private final AtomicLong lastModified = new AtomicLong(0);
/**
* 刷新单个字典事件:数据字典值文本数量超过 5 个就使用批量保存
*/
private int valueEventBatchSize = 5;
/**
* 刷新整个字典事件:数据字典值文本分批次保存,每批次保存 1000 个
*/
private int typeEventBatchSize = 1000;
public void refreshDict(Set dictProviderClasses) {
final long interval = System.currentTimeMillis() - lastModified.get();
final Duration refreshDictInterval = properties.getRefreshDictInterval();
if (interval < refreshDictInterval.toMillis()) {
if (logger.isDebugEnabled()) {
logger.debug("距离上一次刷新字典 {} ms,小于配置的 {} ms,本次事件将不会刷新字典", interval, refreshDictInterval);
}
return;
}
lastModified.set(System.currentTimeMillis());
if (!logger.isDebugEnabled()) {
forEachAllDict(dictProviderClasses, store::store, store::storeSystemDict, store::storeBatch);
} else {
long startTime = System.nanoTime();
forEachAllDict(dictProviderClasses, store::store, store::storeSystemDict, store::storeBatch);
logger.debug("本次刷新数据字典耗时 {} ms,传入刷新范围:{}", (System.nanoTime() - startTime) / 100_0000.0, dictProviderClasses);
}
}
/**
* 循环获取所有 {@link DictProvider} 字典提供者提供的所有字典数据信息,把获取到的字典对象和字典值数据存入到 {@link DictStore} 存储对象中
*
* @param dictProviderClasses 只获取特定的 {@link DictProvider} 数据,会调用 {@link DictProvider#supportRefresh(Set)} 来判断
* @param dictTypeConsumer 保存字典类型的方法
* @param dictValueConsumer 保存字典值数据的方法
* @since 1.4.11
*/
public void forEachAllDict(final Set dictProviderClasses, final Consumer dictTypeConsumer, final Consumer systemDictTypeConsumer, final Consumer> dictValueConsumer) {
for (final DictProvider provider : providers) {
if (!provider.supportRefresh(dictProviderClasses)) {
continue;
}
// 根据 Provider 参数决定是否存储完整的字典类型信息对象
if (provider.isStoreDictType()) {
final Iterator extends DictTypeVo> typeIterator = provider.dictTypeIterator();
final boolean isSystemProvider = provider instanceof SystemDictProvider;
final List batchSaveDictValueVos = new ArrayList<>(typeEventBatchSize + 50);
typeIterator.forEachRemaining(dictType -> {
dictTypeConsumer.accept(dictType);
if (isSystemProvider) {
// 系统字典单独存储一份
systemDictTypeConsumer.accept(dictType);
}
final List valueVos = fixDictTypeChildren(dictType.getType(), dictType.getChildren());
if (valueVos != null) {
batchSaveDictValueVos.addAll(valueVos);
if (batchSaveDictValueVos.size() > typeEventBatchSize) {
dictValueConsumer.accept(batchSaveDictValueVos.iterator());
batchSaveDictValueVos.clear();
}
}
});
if (!batchSaveDictValueVos.isEmpty()) {
dictValueConsumer.accept(batchSaveDictValueVos.iterator());
}
} else {
dictValueConsumer.accept(provider.dictValueIterator());
}
}
}
@Override
public void afterPropertiesSet() throws Exception {
if (properties.isOnBootRefreshDict()) {
refreshDict(null);
}
}
/**
* 处理系统内部发起的刷新数据字典事件
*
* @param event RefreshDictEvent 事件
*/
@Async
@EventListener
public void eventListenerRefreshEvent(final RefreshDictEvent event) {
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictEvent] 应用内部通知刷新字典事件。事件内容:{}", event.getSource());
}
refreshDict(event.getDictProviderClasses());
}
/**
* 刷新单个字典值文本信息。
*
* @param event RefreshDictValueEvent 事件
* @since 1.4.4
*/
@Async
@EventListener
public void refreshDictValueEvent(final RefreshDictValueEvent event) {
final Iterable dictValueVos = event.getSource();
ArrayList list;
if (dictValueVos instanceof Collection) {
list = new ArrayList<>((Collection) dictValueVos);
} else {
list = new ArrayList<>();
for (DictValueVo valueVo : dictValueVos) {
list.add(valueVo);
}
}
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.value] 刷新字典值文本信息,共有 {} 条数据", list.size());
}
Set systemDictTypeKeys = store.systemDictTypeKeys();
removeSystemDictValue(list.iterator(), systemDictTypeKeys);
if (!list.isEmpty()) {
if (list.size() > valueEventBatchSize) {
// 刷新数据字典值文本时,超过5条数据的采用批量写入方式
store.storeBatch(list.iterator());
} else {
store.store(list.iterator());
}
}
}
/**
* 检测需要刷新的字典文本列表,从中移除属于系统字典的文本信息,不允许通过刷新字典的方式修改系统字典文本
*
* @param iterator 迭代器
* @param systemDictTypeKeys 系统字典代码列表
* @since 1.5.0
*/
private void removeSystemDictValue(Iterator iterator, Set systemDictTypeKeys) {
while (iterator.hasNext()) {
DictValueVo valueVo = iterator.next();
String dictType = valueVo.getDictType();
if (systemDictTypeKeys.contains(dictType)) {
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.value] 刷新字典值涉及的字典类型代码 {},此类型为系统字典类型,无法通过事件方式刷新字典值,已忽略", dictType);
}
iterator.remove();
}
}
}
/**
* 刷新单个字典值文本信息时根据 {@link RefreshDictValueEvent#isUpdateDictType()} 参数决定是否维护的字典类型对象里面的字典值列表信息
*
* @param event RefreshDictValueEvent 事件
* @since 1.4.5
*/
@Async
@EventListener
public void refreshDictValueEventUpdateDictType(final RefreshDictValueEvent event) {
if (!event.isUpdateDictType()) {
return;
}
final Iterable dictValueVos = event.getSource();
final boolean removeDictType = event.isRemoveDictType();
// 把字典值列表通过字典类型收集起来
Multimap multimap = ArrayListMultimap.create();
dictValueVos.forEach(valueVo -> multimap.put(valueVo.getDictType(), valueVo));
final Set keySet = multimap.keySet();
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.type] 刷新字典值涉及的字典类型代码 {}", keySet);
}
Set systemDictTypeKeys = store.systemDictTypeKeys();
for (final String dictType : keySet) {
if (systemDictTypeKeys.contains(dictType)) {
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.type] 刷新字典值涉及的字典类型代码 {},此类型为系统字典类型,无法通过事件方式刷新字典值,已忽略", dictType);
}
continue;
}
// 处理维护字典类型代码的字典信息
maintainHandleDictType(dictType, new ArrayList<>(multimap.get(dictType)), removeDictType);
}
}
/**
* 维护处理字典类型信息
*
* @param dictType 字典类型代码
* @param valueVos 字典值列表
* @param removeDictType 没有字典值列表时是否删除字典类型
* @since 1.4.5
*/
private void maintainHandleDictType(final String dictType, final List valueVos, final boolean removeDictType) {
final DictTypeVo dictTypeVo = store.getDictType(dictType);
final List valueVosUpdate = valueVos.stream().filter(vo -> vo.getTitle() != null).collect(Collectors.toList());
if (dictTypeVo == null) {
// 不存在字典类型信息,新增一个字典类型信息
final DictTypeVo newType = new DictTypeVo("RefreshDictValueEvent Add", dictType, "RefreshDictValueEvent Add", valueVosUpdate);
store.store(newType);
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.type] 有一个新的字典类型被加入到缓存中 {}", newType);
}
return;
}
final List children = dictTypeVo.getChildren();
if (children == null || children.isEmpty()) {
// 原字典类型无字典值列表,增加新的字典值列表
dictTypeVo.setChildren(valueVosUpdate);
store.store(dictTypeVo);
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.type] 旧字典类型无字典值,更新后字典类型有字典值 {}", dictTypeVo);
}
return;
}
final List valueVosRemove = valueVos.stream().filter(vo -> vo.getTitle() == null).collect(Collectors.toList());
maintainHandleDictTypeDiffUpdate(dictTypeVo, valueVosUpdate, valueVosRemove, removeDictType);
}
/**
* 维护处理字典类型信息(处理字典值列表差异合并)
*
* @param dictTypeVo 字典类型对象
* @param valueVosUpdate 需要更新或新增的字典值列表
* @param valueVosRemove 需要删除的字典值类别
* @param removeDictType 没有字典值列表时是否删除字典类型
* @since 1.4.5.1
*/
private void maintainHandleDictTypeDiffUpdate(final DictTypeVo dictTypeVo, final List valueVosUpdate,
final List valueVosRemove, final boolean removeDictType) {
final List children = dictTypeVo.getChildren();
// 从列表移除需要删除的字典列表
children.removeIf(vo1 -> {
for (final DictValueVo vo2 : valueVosRemove) {
if (Objects.equals(vo1.getValue(), vo2.getValue())) {
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.type] 字典类型 {} 的 {} = {} 字典值被删除", dictTypeVo.getType(), vo1.getValue(), vo1.getTitle());
}
return true;
}
}
return false;
});
// 维护需要替换的字典值列表信息
children.addAll(valueVosUpdate);
Map map = new LinkedHashMap<>();
children.forEach(valueVo -> map.put(valueVo.getValue(), valueVo));
dictTypeVo.setChildren(removeDictType && map.isEmpty() ? null : new ArrayList<>(map.values()));
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictValueEvent.type] 字典类型的字典值列表被更新,共有 {} 条数据", dictTypeVo.getChildren().size());
}
store.store(dictTypeVo);
}
/**
* 刷新单个字典值类型信息(包含此字典类型的字典值列表)
*
* @param event RefreshDictTypeEvent 事件
* @since 1.4.5
*/
@Async
@EventListener
public void refreshDictTypeEvent(final RefreshDictTypeEvent event) {
final Iterable dictTypeVos = event.getSource();
Set systemDictTypeKeys = store.systemDictTypeKeys();
dictTypeVos.forEach(dictType -> {
if (systemDictTypeKeys.contains(dictType.getType())) {
if (logger.isDebugEnabled()) {
logger.debug("[RefreshDictTypeEvent] 刷新字典值涉及的字典类型代码 {},此类型为系统字典类型,无法通过事件方式刷新字典值,已忽略", dictType.getType());
}
return;
}
final List dictValueVos = fixDictTypeChildren(dictType.getType(), dictType.getChildren());
if (dictValueVos != null) {
store.removeDictType(dictType.getType());
store.store(dictValueVos.iterator());
}
store.store(dictType);
});
}
@Nullable
private List fixDictTypeChildren(final String dictType, final List dictValueVos) {
if (dictValueVos == null) {
return null;
}
for (final DictValueVo valueVo : dictValueVos) {
valueVo.setDictType(dictType);
}
return dictValueVos;
}
}