Sfoglia il codice sorgente

feign请求转发配置优化

woody 5 mesi fa
parent
commit
df53648911

+ 1 - 17
framework-feign/src/main/java/com/chelvc/framework/feign/config/FeignProperties.java

@@ -20,29 +20,13 @@ public class FeignProperties {
     /**
      * 请求转发配置
      */
-    private final Forward forward = new Forward();
+    private List<Forward> forwards = Collections.emptyList();
 
     /**
      * 请求转发配置
      */
     @Data
     public static class Forward {
-        /**
-         * 是否启用
-         */
-        private boolean enabled;
-
-        /**
-         * 请求转发映射列表
-         */
-        private List<Mapping> mappings = Collections.emptyList();
-    }
-
-    /**
-     * 请求转发映射
-     */
-    @Data
-    public static class Mapping {
         /**
          * 原服务
          */

+ 21 - 31
framework-feign/src/main/java/com/chelvc/framework/feign/interceptor/FeignInvokeInterceptor.java

@@ -36,25 +36,13 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
  */
 @Slf4j
 public class FeignInvokeInterceptor implements RequestInterceptor {
-    private final List<FeignProperties.Mapping> forwards;
+    private final List<FeignProperties.Forward> forwards;
 
     public FeignInvokeInterceptor(@NonNull ApplicationContext applicationContext) {
-        this.forwards = this.mappings(applicationContext);
-    }
-
-    /**
-     * 获取请求转发映射表
-     *
-     * @param applicationContext 应用上下文
-     * @return 请求转发映射列表
-     */
-    private List<FeignProperties.Mapping> mappings(ApplicationContext applicationContext) {
-        FeignProperties.Forward forward = applicationContext.getBean(FeignProperties.class).getForward();
-        if (!forward.isEnabled()) {
-            return Collections.emptyList();
-        }
-        List<FeignProperties.Mapping> mappings = ObjectUtils.ifNull(
-                forward.getMappings(), Lists::newArrayList, Lists::newArrayList
+        // 加载请求转发配置
+        FeignProperties properties = applicationContext.getBean(FeignProperties.class);
+        List<FeignProperties.Forward> forwards = ObjectUtils.ifNull(
+                properties.getForwards(), Lists::newArrayList, Lists::newArrayList
         );
         List<Resource> resources = ApplicationContextHolder.getApplicationResources();
         RequestMappingHandlerMapping handlers = applicationContext.getBean(RequestMappingHandlerMapping.class);
@@ -65,17 +53,18 @@ public class FeignInvokeInterceptor implements RequestInterceptor {
             for (Resource resource : resources) {
                 String name = ApplicationContextHolder.getApplicationName(resource);
                 if (StringUtils.isEmpty(name) || ObjectUtils.equals(name, server)
-                        || mappings.stream().anyMatch(mapping -> Objects.equals(mapping.getSource(), name))) {
+                        || forwards.stream().anyMatch(forward -> ObjectUtils.equals(forward.getSource(), "*")
+                        || Objects.equals(forward.getSource(), name))) {
                     continue;
                 }
-                FeignProperties.Mapping mapping = new FeignProperties.Mapping();
-                mapping.setSource(name);
-                mapping.setTarget(HostUtils.DEFAULT_LOCAL_NAME + ":" + port);
-                mapping.setPrefixed(prefixes.contains(name));
-                mappings.add(mapping);
+                FeignProperties.Forward forward = new FeignProperties.Forward();
+                forward.setSource(name);
+                forward.setTarget(HostUtils.DEFAULT_LOCAL_NAME + ":" + port);
+                forward.setPrefixed(prefixes.contains(name));
+                forwards.add(forward);
             }
         }
-        return mappings.isEmpty() ? Collections.emptyList() : Lists.newArrayList(mappings);
+        this.forwards = forwards.isEmpty() ? Collections.emptyList() : Lists.newArrayList(forwards);
     }
 
     /**
@@ -113,17 +102,18 @@ public class FeignInvokeInterceptor implements RequestInterceptor {
         // 请求转发处理
         if (ObjectUtils.notEmpty(this.forwards)) {
             Target<?> target = template.feignTarget();
-            for (FeignProperties.Mapping mapping : this.forwards) {
-                if (ObjectUtils.equals(mapping.getSource(), target.name())
-                        || ObjectUtils.equals(mapping.getSource(), "*")) {
-                    if (mapping.isPrefixed()) {
+            for (FeignProperties.Forward forward : this.forwards) {
+                if (ObjectUtils.equals(forward.getSource(), target.name())
+                        || ObjectUtils.equals(forward.getSource(), "*")) {
+                    if (forward.isPrefixed()) {
                         template.uri(HttpUtils.uri(target.name(), template.path()));
                     }
-                    if (!Objects.equals(mapping.getTarget(), target.name())) {
+                    if (StringUtils.notEmpty(forward.getTarget())
+                            && !Objects.equals(forward.getTarget(), target.name())) {
                         URI uri = URI.create(target.url());
-                        String url = uri.getScheme() + "://" + mapping.getTarget();
+                        String url = uri.getScheme() + "://" + forward.getTarget();
                         template.target(url);
-                        template.feignTarget(new Target.HardCodedTarget<>(target.type(), mapping.getTarget(), url));
+                        template.feignTarget(new Target.HardCodedTarget<>(target.type(), forward.getTarget(), url));
                     }
                     break;
                 }

+ 28 - 0
framework-group/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.chelvc.framework</groupId>
+        <artifactId>framework-dependencies</artifactId>
+        <version>1.0.0-RELEASE</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>framework-group</artifactId>
+    <version>1.0.0-RELEASE</version>
+
+    <properties>
+        <framework-base.version>1.0.0-RELEASE</framework-base.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.chelvc.framework</groupId>
+            <artifactId>framework-base</artifactId>
+            <version>${framework-base.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 8 - 0
framework-group/src/main/java/com/chelvc/framework/group/AnnotationGroupHandler.java

@@ -0,0 +1,8 @@
+package com.chelvc.framework.group;
+
+/**
+ * @author Woody
+ * @date 2024/9/11
+ */
+public class AnnotationGroupHandler {
+}

+ 33 - 0
framework-group/src/main/java/com/chelvc/framework/group/DefaultGroupHandler.java

@@ -0,0 +1,33 @@
+package com.chelvc.framework.group;
+
+import lombok.Getter;
+import lombok.NonNull;
+
+/**
+ * @author Woody
+ * @date 2024/9/11
+ */
+@Getter
+public class DefaultGroupHandler implements GroupHandler {
+    private final int count;
+    private final String scene;
+    private final boolean lazy;
+    private final boolean async;
+    private final boolean cacheable;
+    private final GroupSelector selector;
+
+    public DefaultGroupHandler(@NonNull String scene, int count, boolean lazy, boolean async, boolean cacheable,
+                               @NonNull GroupSelector selector) {
+        this.scene = scene;
+        this.count = count;
+        this.lazy = lazy;
+        this.async = async;
+        this.cacheable = cacheable;
+        this.selector = selector;
+    }
+
+    @Override
+    public boolean isExpired() {
+        return false;
+    }
+}

+ 26 - 0
framework-group/src/main/java/com/chelvc/framework/group/DeviceGroupSelector.java

@@ -0,0 +1,26 @@
+package com.chelvc.framework.group;
+
+import java.util.zip.CRC32;
+
+import com.chelvc.framework.base.context.SessionContextHolder;
+import com.chelvc.framework.common.util.StringUtils;
+import lombok.NonNull;
+
+/**
+ * 基于客户端设备号分组选择器实现
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+public class DeviceGroupSelector implements GroupSelector {
+    @Override
+    public int grouping(int count, @NonNull Object... args) {
+        String device = SessionContextHolder.getDevice();
+        if (StringUtils.isEmpty(device)) {
+            return -1;
+        }
+        CRC32 crc = new CRC32();
+        crc.update(device.getBytes());
+        return (int) (Math.abs(crc.getValue()) % count);
+    }
+}

+ 82 - 0
framework-group/src/main/java/com/chelvc/framework/group/GroupCache.java

@@ -0,0 +1,82 @@
+package com.chelvc.framework.group;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * 分组缓存接口
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+public interface GroupCache {
+    /**
+     * 获取分组
+     *
+     * @param key   分组标识
+     * @param scene 分组场景
+     * @return 分组数字
+     */
+    int getGroup(Object key, String scene);
+
+    /**
+     * 批量获取分组
+     *
+     * @param key    分组标识
+     * @param scenes 分组场景集合
+     * @return 分组场景/数字映射表
+     */
+    Map<String, Integer> getGroups(Object key, Collection<String> scenes);
+
+    /**
+     * 设置分组
+     *
+     * @param key   分组标识
+     * @param scene 分组场景
+     * @param group 分组数字
+     */
+    void setGroup(Object key, String scene, int group);
+
+    /**
+     * 批量设置分组
+     *
+     * @param key    分组标识
+     * @param groups 分组场景/数字映射表
+     */
+    void setGroups(Object key, Map<String, Integer> groups);
+
+    /**
+     * 初始化分组,当分组场景已存在分组时返回已经存在分组,否则返回当前设置分组
+     *
+     * @param key   分组标识
+     * @param scene 分组场景
+     * @param group 分组数字
+     * @return 分组数字
+     */
+    int initializeGroup(Object key, String scene, int group);
+
+    /**
+     * 批量初始化分组,当分组场景已存在分组时返回已经存在分组,否则返回当前设置分组
+     *
+     * @param key    分组标识
+     * @param groups 分组场景/数字映射表
+     * @return 分组场景/数字映射表
+     */
+    Map<String, Integer> initializeGroups(Object key, Map<String, Integer> groups);
+
+    /**
+     * 移除分组
+     *
+     * @param key   分组标识
+     * @param scene 分组场景
+     */
+    void removeGroup(Object key, String scene);
+
+    /**
+     * 移除分组
+     *
+     * @param key    分组标识
+     * @param scenes 分组场景集合
+     */
+    void removeGroups(Object key, Collection<String> scenes);
+}

+ 25 - 0
framework-group/src/main/java/com/chelvc/framework/group/GroupEvent.java

@@ -0,0 +1,25 @@
+package com.chelvc.framework.group;
+
+import com.chelvc.framework.base.context.BasicEvent;
+import lombok.Getter;
+import lombok.NonNull;
+
+/**
+ * 分组事件
+ *
+ * @author Woody
+ * @date 2024/9/11
+ */
+@Getter
+public class GroupEvent extends BasicEvent {
+    private final Object key;
+    private final String scene;
+    private final int group;
+
+    public GroupEvent(Object source, @NonNull Object key, @NonNull String scene, int group) {
+        super(source);
+        this.key = key;
+        this.scene = scene;
+        this.group = group;
+    }
+}

+ 56 - 0
framework-group/src/main/java/com/chelvc/framework/group/GroupHandler.java

@@ -0,0 +1,56 @@
+package com.chelvc.framework.group;
+
+/**
+ * @author Woody
+ * @date 2024/9/11
+ */
+public interface GroupHandler {
+    /**
+     * 获取分组数量
+     *
+     * @return 分组数量
+     */
+    int getCount();
+
+    /**
+     * 获取分组场景
+     *
+     * @return 分组场景
+     */
+    String getScene();
+
+    /**
+     * 是否延迟分组
+     *
+     * @return true/false
+     */
+    boolean isLazy();
+
+    /**
+     * 是否异步分组
+     *
+     * @return true/false
+     */
+    boolean isAsync();
+
+    /**
+     * 是否已过期
+     *
+     * @return true/false
+     */
+    boolean isExpired();
+
+    /**
+     * 是否缓存分组结果
+     *
+     * @return true/false
+     */
+    boolean isCacheable();
+
+    /**
+     * 获取分组选择器对象
+     *
+     * @return 分组选择器对象
+     */
+    GroupSelector getSelector();
+}

+ 18 - 0
framework-group/src/main/java/com/chelvc/framework/group/GroupSelector.java

@@ -0,0 +1,18 @@
+package com.chelvc.framework.group;
+
+/**
+ * 分组选择器接口
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+public interface GroupSelector {
+    /**
+     * 分组 当分组结果 < 0 表示未分组, = 0 表示对照组,> 0 表示实验组
+     *
+     * @param count 分组数量
+     * @param args  方法输入/出参数数组
+     * @return 分组编号
+     */
+    int grouping(int count, Object... args);
+}

+ 18 - 0
framework-group/src/main/java/com/chelvc/framework/group/IdentityGroupSelector.java

@@ -0,0 +1,18 @@
+package com.chelvc.framework.group;
+
+import com.chelvc.framework.base.context.SessionContextHolder;
+import lombok.NonNull;
+
+/**
+ * 基于用户ID分组选择器实现
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+public class IdentityGroupSelector implements GroupSelector {
+    @Override
+    public int grouping(int count, @NonNull Object... args) {
+        Long id = SessionContextHolder.getId();
+        return id == null ? -1 : (int) (id % count);
+    }
+}

+ 85 - 0
framework-group/src/main/java/com/chelvc/framework/group/annotation/Group.java

@@ -0,0 +1,85 @@
+package com.chelvc.framework.group.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.chelvc.framework.common.model.Invoking;
+import com.chelvc.framework.common.model.Platform;
+import com.chelvc.framework.common.model.Terminal;
+import com.chelvc.framework.group.GroupSelector;
+
+/**
+ * 场景分组注解
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+@Documented
+@Target({})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Group {
+    /**
+     * 获取分组场景
+     *
+     * @return 分组场景
+     */
+    String scene();
+
+    /**
+     * 获取分组数量
+     *
+     * @return 分组数量
+     */
+    int count() default 2;
+
+    /**
+     * 是否异步分组
+     *
+     * @return true/false
+     */
+    boolean async() default false;
+
+    /**
+     * 获取渠道数组
+     *
+     * @return 渠道数组
+     */
+    String[] channels() default {};
+
+    /**
+     * 获取版本数组
+     *
+     * @return 版本数组
+     */
+    Version[] versions() default {};
+
+    /**
+     * 获取平台数组
+     *
+     * @return 平台数组
+     */
+    Platform[] platforms() default {};
+
+    /**
+     * 获取终端数组
+     *
+     * @return 终端数组
+     */
+    Terminal[] terminals() default {};
+
+    /**
+     * 获取分组选择器对象
+     *
+     * @return 分组选择器对象
+     */
+    Class<? extends GroupSelector> selector();
+
+    /**
+     * 获取分组时机
+     *
+     * @return 分组时机
+     */
+    Invoking invoking() default Invoking.REQUEST;
+}

+ 25 - 0
framework-group/src/main/java/com/chelvc/framework/group/annotation/Groups.java

@@ -0,0 +1,25 @@
+package com.chelvc.framework.group.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 多场景分组注解
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Groups {
+    /**
+     * 获取场景分组数组
+     *
+     * @return 场景分组数组
+     */
+    Group[] value();
+}

+ 41 - 0
framework-group/src/main/java/com/chelvc/framework/group/annotation/Version.java

@@ -0,0 +1,41 @@
+package com.chelvc.framework.group.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.chelvc.framework.common.model.Compare;
+import com.chelvc.framework.common.model.Terminal;
+
+/**
+ * 客户端版本号注解
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+@Documented
+@Target({})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Version {
+    /**
+     * 获取版本号
+     *
+     * @return 版本号
+     */
+    String value();
+
+    /**
+     * 获取客户终端
+     *
+     * @return 客户终端
+     */
+    Terminal terminal();
+
+    /**
+     * 获取版本比较方式
+     *
+     * @return 比较方式
+     */
+    Compare compare() default Compare.EQ;
+}

+ 25 - 0
framework-group/src/main/java/com/chelvc/framework/group/annotation/Versions.java

@@ -0,0 +1,25 @@
+package com.chelvc.framework.group.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 多客户端版本号注解
+ *
+ * @author Woody
+ * @date 2024/9/8
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Versions {
+    /**
+     * 获取客户端版本号注解数组
+     *
+     * @return 客户端版本号注解数组
+     */
+    Version[] value();
+}

+ 1 - 0
pom.xml

@@ -25,6 +25,7 @@
         <module>framework-rocketmq</module>
         <module>framework-security</module>
         <module>framework-sms</module>
+        <module>framework-group</module>
         <module>framework-aliyun</module>
         <module>framework-upload</module>
         <module>framework-wechat</module>