fix: 解决 ConfigServiceImpl 与 SiteSnapshotServiceImpl 循环依赖

- 移除 SiteSnapshotServiceImpl 对 ConfigService 的依赖,直接使用 SiteConfigMapper
- ConfigServiceImpl/SitePagesServiceImpl/RiskRuleServiceImpl 改用 ApplicationEvent 异步触发快照更新
- 新增 SnapshotUpdateEvent 和 SnapshotUpdateListener
- ParApplication 添加 @EnableAsync 支持异步事件处理
- AdminController 中 updateSnapshot 调用改为发布事件
This commit is contained in:
mediabot-pt
2026-07-07 11:17:22 +08:00
parent b25aa82c73
commit c823878ae0
9 changed files with 344 additions and 20 deletions

View File

@@ -0,0 +1,17 @@
package com.par.core.event;
import lombok.Getter;
/**
* 快照更新事件
* 当脚本、页面配置或风险规则发生变更时触发
*/
@Getter
public class SnapshotUpdateEvent {
private final String siteId;
public SnapshotUpdateEvent(String siteId) {
this.siteId = siteId;
}
}

View File

@@ -0,0 +1,30 @@
package com.par.core.event;
import com.par.core.service.SiteSnapshotService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* 快照更新事件监听器
* 异步处理,避免阻塞主流程
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class SnapshotUpdateListener {
private final SiteSnapshotService snapshotService;
@Async
@EventListener
public void handleSnapshotUpdate(SnapshotUpdateEvent event) {
try {
snapshotService.updateSnapshot(event.getSiteId());
} catch (Exception e) {
log.warn("快照更新失败 siteId={}: {}", event.getSiteId(), e.getMessage());
}
}
}

View File

@@ -4,12 +4,13 @@ import com.par.common.util.HmacUtil;
import com.par.core.dto.SiteConfigDTO;
import com.par.core.entity.SiteConfig;
import com.par.core.enums.ConfigStatus;
import com.par.core.event.SnapshotUpdateEvent;
import com.par.core.mapper.SiteConfigMapper;
import com.par.core.service.ConfigService;
import com.par.core.service.ManifestVersionService;
import com.par.core.service.SiteSnapshotService;
import com.par.core.storage.CachedStorageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import java.util.List;
@@ -22,16 +23,16 @@ public class ConfigServiceImpl implements ConfigService {
private final ManifestVersionService versionService;
private final SiteConfigMapper siteConfigMapper;
private final CachedStorageService storageService;
private final SiteSnapshotService snapshotService;
private final ApplicationEventPublisher eventPublisher;
public ConfigServiceImpl(ManifestVersionService versionService,
SiteConfigMapper siteConfigMapper,
CachedStorageService storageService,
SiteSnapshotService snapshotService) {
ApplicationEventPublisher eventPublisher) {
this.versionService = versionService;
this.siteConfigMapper = siteConfigMapper;
this.storageService = storageService;
this.snapshotService = snapshotService;
this.eventPublisher = eventPublisher;
}
@Override
@@ -89,8 +90,8 @@ public class ConfigServiceImpl implements ConfigService {
siteConfigMapper.insert(config);
versionService.increment(siteId);
// 触发快照更新(异步更新 draft)
try { snapshotService.updateSnapshot(siteId); } catch (Exception e) { log.warn("快照更新失败 siteId={}: {}", siteId, e.getMessage()); }
// 发布事件,异步触发快照更新
eventPublisher.publishEvent(new SnapshotUpdateEvent(siteId));
log.info("Config submitted: siteId={}, version={}, id={}, scriptPath={}", siteId, version, config.getId(), scriptPath);
return config;
}

View File

@@ -3,12 +3,13 @@ package com.par.core.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.par.core.entity.RiskRule;
import com.par.core.event.SnapshotUpdateEvent;
import com.par.core.mapper.RiskRuleMapper;
import com.par.core.service.ManifestVersionService;
import com.par.core.service.RiskRuleService;
import com.par.core.service.SiteSnapshotService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import java.util.*;
@@ -22,7 +23,7 @@ public class RiskRuleServiceImpl implements RiskRuleService {
private final RiskRuleMapper mapper;
private final com.par.core.storage.CachedStorageService storageService;
private final com.par.core.service.SiteService siteService;
private final SiteSnapshotService snapshotService;
private final ApplicationEventPublisher eventPublisher;
private static final ObjectMapper om = new ObjectMapper();
private RiskRule findByIdentifier(String identifier) {
@@ -122,11 +123,10 @@ public class RiskRuleServiceImpl implements RiskRuleService {
.filter(s -> s.getSiteType() != null && siteType.equals(s.getSiteType().getValue()))
.toList();
for (var site : sites) {
try { snapshotService.updateSnapshot(site.getSiteId()); }
catch (Exception e) { log.warn("快照更新失败 siteId={}: {}", site.getSiteId(), e.getMessage()); }
eventPublisher.publishEvent(new SnapshotUpdateEvent(site.getSiteId()));
}
} catch (Exception e) {
log.warn("批量快照更新失败 siteType={}: {}", siteType, e.getMessage());
log.warn("批量快照更新事件发布失败 siteType={}: {}", siteType, e.getMessage());
}
}

View File

@@ -3,12 +3,13 @@ package com.par.core.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.par.core.entity.SitePages;
import com.par.core.event.SnapshotUpdateEvent;
import com.par.core.mapper.SitePagesMapper;
import com.par.core.service.ManifestVersionService;
import com.par.core.service.SitePagesService;
import com.par.core.service.SiteSnapshotService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import java.util.*;
@@ -21,7 +22,7 @@ public class SitePagesServiceImpl implements SitePagesService {
private final ManifestVersionService versionService;
private final SitePagesMapper mapper;
private final com.par.core.storage.CachedStorageService storageService;
private final SiteSnapshotService snapshotService;
private final ApplicationEventPublisher eventPublisher;
private static final ObjectMapper om = new ObjectMapper();
@Override
@@ -84,8 +85,8 @@ public class SitePagesServiceImpl implements SitePagesService {
String storagePath = String.format("pages/%s/v%s.json", siteId, version);
storageService.store(storagePath, json);
versionService.increment(siteId);
// 触发快照更新
try { snapshotService.updateSnapshot(siteId); } catch (Exception e) { log.warn("快照更新失败 siteId={}: {}", siteId, e.getMessage()); }
// 发布事件,异步触发快照更新
eventPublisher.publishEvent(new SnapshotUpdateEvent(siteId));
log.info("页面配置已保存: siteId={}, version={}, path={}", siteId, version, storagePath);
} catch (Exception e) {
log.error("保存页面配置失败 siteId={}", siteId, e);

View File

@@ -11,7 +11,6 @@ import com.par.core.mapper.RiskRuleMapper;
import com.par.core.mapper.SiteConfigMapper;
import com.par.core.mapper.SiteMapper;
import com.par.core.mapper.SiteSnapshotMapper;
import com.par.core.service.ConfigService;
import com.par.core.service.SitePagesService;
import com.par.core.service.SiteSnapshotService;
import com.par.core.storage.CachedStorageService;
@@ -36,7 +35,6 @@ public class SiteSnapshotServiceImpl implements SiteSnapshotService {
private final SiteSnapshotMapper snapshotMapper;
private final SiteConfigMapper siteConfigMapper;
private final SiteMapper siteMapper;
private final ConfigService configService;
private final SitePagesService sitePagesService;
private final RiskRuleMapper riskRuleMapper;
private final CachedStorageService storageService;
@@ -52,7 +50,7 @@ public class SiteSnapshotServiceImpl implements SiteSnapshotService {
String siteType = site != null && site.getSiteType() != null ? site.getSiteType().getValue() : null;
// 1. 脚本
SiteConfig latest = configService.getLatestConfig(siteId);
SiteConfig latest = siteConfigMapper.selectLatestBySiteId(siteId);
if (latest != null && latest.getScriptStoragePath() != null && !latest.getScriptStoragePath().isBlank()) {
try {
String script = storageService.read(latest.getScriptStoragePath());