Browse Source

修复多服务打包运行feign请求转发异常问题

woody 8 months ago
parent
commit
fa3a73f007

+ 6 - 1
framework-feign/src/main/java/com/chelvc/framework/feign/config/FeignConfigurer.java

@@ -1,10 +1,12 @@
 package com.chelvc.framework.feign.config;
 
+import com.chelvc.framework.base.config.MultiserverMvcConfigurer;
 import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.feign.encoder.CustomizeEncoder;
 import com.chelvc.framework.feign.encoder.CustomizeQueryEncoder;
 import com.chelvc.framework.feign.interceptor.FeignFailureInterceptor;
 import com.chelvc.framework.feign.interceptor.FeignInvokeInterceptor;
+import com.chelvc.framework.feign.interceptor.MultiserverFeignInvokeInterceptor;
 import feign.QueryMapEncoder;
 import feign.codec.Decoder;
 import feign.codec.Encoder;
@@ -80,6 +82,9 @@ public class FeignConfigurer {
     @Bean
     @ConditionalOnMissingBean(FeignInvokeInterceptor.class)
     public FeignInvokeInterceptor feignInvokeInterceptor(ApplicationContext applicationContext) {
-        return new FeignInvokeInterceptor(applicationContext);
+        if (applicationContext.containsBean(MultiserverMvcConfigurer.class.getName())) {
+            return new MultiserverFeignInvokeInterceptor(applicationContext);
+        }
+        return new FeignInvokeInterceptor();
     }
 }

+ 1 - 77
framework-feign/src/main/java/com/chelvc/framework/feign/interceptor/FeignInvokeInterceptor.java

@@ -1,32 +1,14 @@
 package com.chelvc.framework.feign.interceptor;
 
-import java.net.URI;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.base.context.Session;
 import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.base.context.Using;
-import com.chelvc.framework.base.util.HttpUtils;
 import com.chelvc.framework.common.model.Platform;
 import com.chelvc.framework.common.model.Terminal;
-import com.chelvc.framework.common.util.HostUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
-import com.chelvc.framework.common.util.StringUtils;
-import com.chelvc.framework.feign.config.FeignProperties;
-import com.google.common.collect.Lists;
 import feign.RequestInterceptor;
 import feign.RequestTemplate;
-import feign.Target;
 import lombok.NonNull;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.io.Resource;
-import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 
 /**
  * Feign调用处理拦截器
@@ -34,45 +16,13 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
  * @author Woody
  * @date 2024/1/30
  */
-@Slf4j
 public class FeignInvokeInterceptor implements RequestInterceptor {
-    private final List<FeignProperties.Forward> forwards;
-
-    public FeignInvokeInterceptor(@NonNull ApplicationContext applicationContext) {
-        // 加载请求转发配置
-        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);
-        Set<String> prefixes = ObjectUtils.ifNull(handlers.getPathPrefixes(), Map::keySet, Collections::emptySet);
-        if (ObjectUtils.notEmpty(resources)) {
-            int port = ApplicationContextHolder.getPort(applicationContext);
-            String server = ApplicationContextHolder.getApplicationName(applicationContext);
-            for (Resource resource : resources) {
-                String name = ApplicationContextHolder.getApplicationName(resource);
-                if (StringUtils.isEmpty(name) || ObjectUtils.equals(name, server)
-                        || forwards.stream().anyMatch(forward -> ObjectUtils.equals(forward.getSource(), "*")
-                        || Objects.equals(forward.getSource(), name))) {
-                    continue;
-                }
-                FeignProperties.Forward forward = new FeignProperties.Forward();
-                forward.setSource(name);
-                forward.setTarget(HostUtils.DEFAULT_LOCAL_NAME + ":" + port);
-                forward.setPrefixed(prefixes.contains(name));
-                forwards.add(forward);
-            }
-        }
-        this.forwards = forwards.isEmpty() ? Collections.emptyList() : Lists.newArrayList(forwards);
-    }
-
     /**
      * 初始化请求头
      *
      * @param template 请求模版对象实例
      */
-    protected void initializeRequestHeader(RequestTemplate template) {
+    protected void initializeRequestHeader(@NonNull RequestTemplate template) {
         Session session = SessionContextHolder.getSession(false);
         if (session == null) {
             return;
@@ -96,32 +46,6 @@ public class FeignInvokeInterceptor implements RequestInterceptor {
 
     @Override
     public void apply(RequestTemplate template) {
-        // 初始化请求头
         this.initializeRequestHeader(template);
-
-        // 请求转发处理
-        if (ObjectUtils.notEmpty(this.forwards)) {
-            Target<?> target = template.feignTarget();
-            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 (StringUtils.notEmpty(forward.getTarget())
-                            && !Objects.equals(forward.getTarget(), target.name())) {
-                        URI uri = URI.create(target.url());
-                        String url = uri.getScheme() + "://" + forward.getTarget();
-                        template.target(url);
-                        template.feignTarget(new Target.HardCodedTarget<>(target.type(), forward.getTarget(), url));
-                    }
-                    break;
-                }
-            }
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("Feign request: {}", template);
-        }
     }
 }

+ 100 - 0
framework-feign/src/main/java/com/chelvc/framework/feign/interceptor/MultiserverFeignInvokeInterceptor.java

@@ -0,0 +1,100 @@
+package com.chelvc.framework.feign.interceptor;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import com.chelvc.framework.base.util.HttpUtils;
+import com.chelvc.framework.common.util.ObjectUtils;
+import com.chelvc.framework.common.util.StringUtils;
+import com.chelvc.framework.feign.config.FeignProperties;
+import feign.RequestTemplate;
+import feign.Target;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.env.Environment;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+/**
+ * 多服务Feign请求调用拦截器
+ *
+ * @author Woody
+ * @date 2024/11/17
+ */
+@Slf4j
+public class MultiserverFeignInvokeInterceptor extends FeignInvokeInterceptor {
+    private final Set<String> servers;
+    private final Map<String, ?> mappings;
+    private final List<FeignProperties.Forward> forwards;
+
+    @SuppressWarnings("unchecked")
+    public MultiserverFeignInvokeInterceptor(@NonNull ApplicationContext applicationContext) {
+        Environment environment = applicationContext.getEnvironment();
+        RequestMappingHandlerMapping handlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
+        Map<String, Predicate<Class<?>>> prefixes = handlerMapping.getPathPrefixes();
+        this.servers = ObjectUtils.isEmpty(prefixes) ? Collections.emptySet() : prefixes.keySet();
+        Object registry = ObjectUtils.getValue(handlerMapping, "mappingRegistry");
+        Map<?, ?> mappings = (Map<?, ?>) ObjectUtils.getValue(registry, "urlLookup");
+        this.mappings = ObjectUtils.isEmpty(mappings) ? Collections.emptyMap() : (Map<String, ?>) mappings;
+        FeignProperties properties = applicationContext.getBean(FeignProperties.class);
+        this.forwards = ObjectUtils.ifEmpty(properties.getForwards(), forwards -> forwards.stream().map(forward -> {
+            FeignProperties.Forward copy = new FeignProperties.Forward();
+            copy.setSource(forward.getSource());
+            copy.setTarget(forward.getTarget());
+            copy.setPrefixed(forward.isPrefixed());
+            if (StringUtils.notEmpty(copy.getTarget())) {
+                copy.setTarget(environment.resolvePlaceholders(copy.getTarget()));
+            }
+            return copy;
+        }).collect(Collectors.toList()), Collections::emptyList);
+    }
+
+    /**
+     * 请求转发
+     *
+     * @param template 请求模版对象实例
+     */
+    private void forward(RequestTemplate template) {
+        Target<?> target = template.feignTarget();
+        if (!this.servers.contains(target.name())) {
+            return;
+        }
+        for (FeignProperties.Forward forward : this.forwards) {
+            String source = forward.getSource(), mapping = forward.getTarget();
+            if (ObjectUtils.equals(source, target.name()) || ObjectUtils.equals(source, "*")) {
+                if (forward.isPrefixed()) {
+                    String uri = HttpUtils.uri(target.name(), template.path());
+                    if (this.mappings.containsKey(uri)) {
+                        template.uri(uri);
+                    }
+                }
+                if (StringUtils.notEmpty(mapping) && !Objects.equals(mapping, target.name())) {
+                    URI uri = URI.create(target.url());
+                    String url = uri.getScheme() + "://" + mapping;
+                    template.target(url);
+                    template.feignTarget(new Target.HardCodedTarget<>(target.type(), mapping, url));
+                }
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void apply(RequestTemplate template) {
+        super.apply(template);
+
+        if (ObjectUtils.notEmpty(this.forwards)) {
+            this.forward(template);
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("Multiserver feign request: {}", template);
+        }
+    }
+}