|
@@ -0,0 +1,196 @@
|
|
|
+package com.chelvc.framework.base.interceptor;
|
|
|
+
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import java.util.stream.Stream;
|
|
|
+
|
|
|
+import com.chelvc.framework.base.annotation.Group;
|
|
|
+import com.chelvc.framework.base.annotation.Groups;
|
|
|
+import com.chelvc.framework.base.context.ApplicationContextHolder;
|
|
|
+import com.chelvc.framework.base.context.GroupEvent;
|
|
|
+import com.chelvc.framework.base.context.SessionContextHolder;
|
|
|
+import com.chelvc.framework.base.context.ThreadContextHolder;
|
|
|
+import com.chelvc.framework.base.group.GroupHandler;
|
|
|
+import com.chelvc.framework.base.group.GroupStore;
|
|
|
+import com.chelvc.framework.common.model.Caps;
|
|
|
+import com.chelvc.framework.common.model.Invoking;
|
|
|
+import com.chelvc.framework.common.util.ObjectUtils;
|
|
|
+import com.chelvc.framework.common.util.StringUtils;
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.aspectj.lang.ProceedingJoinPoint;
|
|
|
+import org.aspectj.lang.annotation.Around;
|
|
|
+import org.aspectj.lang.annotation.Aspect;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.context.ApplicationContext;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 用户业务分组拦截器
|
|
|
+ *
|
|
|
+ * @author Woody
|
|
|
+ * @date 2024/11/24
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Aspect
|
|
|
+@Component
|
|
|
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
|
|
+public class BusinessGroupInterceptor {
|
|
|
+ private final GroupStore store;
|
|
|
+ private final ApplicationContext applicationContext;
|
|
|
+ private final Map<Class<?>, GroupHandler> handlers = Maps.newConcurrentMap();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断请求是否匹配分组
|
|
|
+ *
|
|
|
+ * @param group 分组注解实例
|
|
|
+ * @return true/false
|
|
|
+ */
|
|
|
+ private boolean matches(Group group) {
|
|
|
+ return StringUtils.notEmpty(group.scene())
|
|
|
+ && (ObjectUtils.isEmpty(group.channels()) || SessionContextHolder.isChannel(group.channels()))
|
|
|
+ && (ObjectUtils.isEmpty(group.versions()) || SessionContextHolder.isVersion(group.versions()))
|
|
|
+ && (ObjectUtils.isEmpty(group.platforms()) || SessionContextHolder.isPlatform(group.platforms()))
|
|
|
+ && (ObjectUtils.isEmpty(group.terminals()) || SessionContextHolder.isTerminal(group.terminals()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化分组处理器
|
|
|
+ *
|
|
|
+ * @param type 处理器类型
|
|
|
+ * @return 分组处理器实例
|
|
|
+ */
|
|
|
+ private GroupHandler initializeGroupHandler(Class<? extends GroupHandler> type) {
|
|
|
+ GroupHandler handler = ApplicationContextHolder.getBean(this.applicationContext, type, false);
|
|
|
+ if (handler == null && (handler = this.handlers.get(type)) == null) {
|
|
|
+ handler = this.handlers.computeIfAbsent(type, k -> ObjectUtils.instance(type));
|
|
|
+ }
|
|
|
+ return handler;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行分组逻辑
|
|
|
+ *
|
|
|
+ * @param target 拦截目标
|
|
|
+ * @param groups 分组注解列表
|
|
|
+ * @param args 分组执行参数
|
|
|
+ */
|
|
|
+ private void execute(Object target, List<Group> groups, Object... args) {
|
|
|
+ Map<String, Caps> stores = null;
|
|
|
+ for (Group group : groups) {
|
|
|
+ try {
|
|
|
+ GroupHandler handler = this.initializeGroupHandler(group.handler());
|
|
|
+ Caps value = handler.execute(group.scene(), args);
|
|
|
+ if (value != null && group.storing()) {
|
|
|
+ if (stores == null) {
|
|
|
+ stores = Maps.newHashMapWithExpectedSize(groups.size());
|
|
|
+ }
|
|
|
+ stores.put(group.scene(), value);
|
|
|
+ } else {
|
|
|
+ value = ObjectUtils.ifNull(value, Caps.NONE);
|
|
|
+ this.applicationContext.publishEvent(new GroupEvent(target, group.scene(), value));
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("Business group handle failed: {}", group.scene(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ stores = ObjectUtils.ifEmpty(stores, this.store::set, Collections::emptyMap);
|
|
|
+ stores.forEach((scene, group) -> {
|
|
|
+ group = ObjectUtils.ifNull(group, Caps.NONE);
|
|
|
+ this.applicationContext.publishEvent(new GroupEvent(target, scene, group));
|
|
|
+ });
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("Business group handle failed", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行分组逻辑
|
|
|
+ *
|
|
|
+ * @param target 拦截目标
|
|
|
+ * @param invoking 分组时间点
|
|
|
+ * @param groups 分组注解列表
|
|
|
+ * @param args 分组执行参数
|
|
|
+ */
|
|
|
+ private void execute(Object target, Invoking invoking, List<Group> groups, Object... args) {
|
|
|
+ List<Group> sync = null, async = null;
|
|
|
+ for (Group group : groups) {
|
|
|
+ if (group.invoking() == invoking) {
|
|
|
+ if (group.async()) {
|
|
|
+ if (async == null) {
|
|
|
+ async = Lists.newLinkedList();
|
|
|
+ }
|
|
|
+ async.add(group);
|
|
|
+ } else {
|
|
|
+ if (sync == null) {
|
|
|
+ sync = Lists.newLinkedList();
|
|
|
+ }
|
|
|
+ sync.add(group);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (ObjectUtils.notEmpty(async)) {
|
|
|
+ List<Group> copy = async;
|
|
|
+ ThreadContextHolder.run(() -> this.execute(target, copy, args));
|
|
|
+ }
|
|
|
+ if (ObjectUtils.notEmpty(sync)) {
|
|
|
+ this.execute(target, sync, args);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 方法调用分组拦截
|
|
|
+ *
|
|
|
+ * @param point 方法拦截点
|
|
|
+ * @param groups 分组注解实例
|
|
|
+ * @return 方法调用结果
|
|
|
+ * @throws Throwable 方法调用异常
|
|
|
+ */
|
|
|
+ @Around("@annotation(groups)")
|
|
|
+ public Object intercept(ProceedingJoinPoint point, Groups groups) throws Throwable {
|
|
|
+ if (Objects.isNull(SessionContextHolder.getId())) {
|
|
|
+ return point.proceed(point.getArgs());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取匹配的分组注解列表
|
|
|
+ List<Group> matches = Stream.of(groups.value()).filter(this::matches)
|
|
|
+ .collect(Collectors.toCollection(Lists::newLinkedList));
|
|
|
+ if (ObjectUtils.isEmpty(matches)) {
|
|
|
+ return point.proceed(point.getArgs());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取已存储分组结果
|
|
|
+ Object target = point.getTarget();
|
|
|
+ try {
|
|
|
+ Set<String> scenes = matches.stream().filter(Group::storing).map(Group::scene).collect(Collectors.toSet());
|
|
|
+ Map<String, Caps> stores = ObjectUtils.ifEmpty(scenes, this.store::get, Collections::emptyMap);
|
|
|
+ stores.forEach((scene, group) -> {
|
|
|
+ if (group != null) {
|
|
|
+ matches.removeIf(annotation -> Objects.equals(annotation.scene(), scene));
|
|
|
+ this.applicationContext.publishEvent(new GroupEvent(target, scene, group));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("Business group handle failed", e);
|
|
|
+ return point.proceed(point.getArgs());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行分组逻辑(方法调用前后)
|
|
|
+ Object[] args = point.getArgs();
|
|
|
+ if (ObjectUtils.notEmpty(matches)) {
|
|
|
+ this.execute(target, Invoking.REQUEST, matches, args);
|
|
|
+ }
|
|
|
+ Object value = point.proceed(args);
|
|
|
+ if (ObjectUtils.notEmpty(matches)) {
|
|
|
+ this.execute(target, Invoking.RESPONSE, matches, value);
|
|
|
+ }
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+}
|