Forráskód Böngészése

:sparkles: 添加新特性,feign 自动降级

冷冷 6 éve
szülő
commit
17c23a1c8a
20 módosított fájl, 963 hozzáadás és 374 törlés
  1. 68 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginConfiguration.java
  2. 129 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginErrorDecoder.java
  3. 57 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginException.java
  4. 69 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginFallbackFactory.java
  5. 0 47
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignClientConfiguration.java
  6. 289 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixFeign.java
  7. 218 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixInvocationHandler.java
  8. 33 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/package-info.java
  9. 90 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/ConcurrentDateFormat.java
  10. 1 1
      pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories
  11. 1 2
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteLogService.java
  12. 5 4
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteTokenService.java
  13. 3 4
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java
  14. 0 38
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/factory/RemoteLogServiceFallbackFactory.java
  15. 0 38
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/factory/RemoteTokenServiceFallbackFactory.java
  16. 0 38
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/factory/RemoteUserServiceFallbackFactory.java
  17. 0 51
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteLogServiceFallbackImpl.java
  18. 0 65
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteTokenServiceFallbackImpl.java
  19. 0 79
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java
  20. 0 7
      pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring.factories

+ 68 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginConfiguration.java

@@ -0,0 +1,68 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+package com.pig4cloud.pigx.common.security.feign;
+
+import com.netflix.hystrix.HystrixCommand;
+import feign.Feign;
+import feign.RequestInterceptor;
+import feign.hystrix.HystrixFeign;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.openfeign.FeignContext;
+import org.springframework.cloud.security.oauth2.client.AccessTokenContextRelay;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Scope;
+import org.springframework.security.oauth2.client.OAuth2ClientContext;
+import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
+
+/**
+ * fegin 配置增强
+ *
+ * @author L.cm
+ */
+@Configuration
+@ConditionalOnClass(Feign.class)
+public class PigxFeginConfiguration {
+
+	@Bean
+	@ConditionalOnProperty("security.oauth2.client.client-id")
+	public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext,
+															OAuth2ProtectedResourceDetails resource,
+															AccessTokenContextRelay accessTokenContextRelay) {
+		return new PigxFeignClientInterceptor(oAuth2ClientContext, resource, accessTokenContextRelay);
+	}
+
+	@Configuration
+	@ConditionalOnClass({HystrixCommand.class, HystrixFeign.class})
+	protected static class HystrixFeignConfiguration {
+		@Bean
+		@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+		@ConditionalOnProperty("feign.hystrix.enabled")
+		public Feign.Builder feignHystrixBuilder(FeignContext feignContext) {
+			return PigxHystrixFeign.builder(feignContext)
+					.decode404()
+					.errorDecoder(new PigxFeginErrorDecoder());
+		}
+	}
+
+}

+ 129 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginErrorDecoder.java

@@ -0,0 +1,129 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+package com.pig4cloud.pigx.common.security.feign;
+
+import cn.hutool.core.io.IoUtil;
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import com.pig4cloud.pigx.common.core.util.R;
+import com.pig4cloud.pigx.common.security.util.ConcurrentDateFormat;
+import feign.Response;
+import feign.RetryableException;
+import feign.codec.ErrorDecoder;
+import org.springframework.lang.Nullable;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.text.ParseException;
+import java.time.ZoneId;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.TimeZone;
+
+import static feign.Util.checkNotNull;
+import static java.lang.String.format;
+import static java.util.Locale.US;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+/**
+ * 异常处理,将返回的数据反序列化成 R
+ *
+ * @author L.cm
+ */
+public class PigxFeginErrorDecoder extends ErrorDecoder.Default {
+	private final RetryAfterDecoder retryAfterDecoder = new RetryAfterDecoder();
+	private static final String REGEX = "^[0-9]+$";
+
+
+	@Override
+	public Exception decode(String methodKey, Response response) {
+		PigxFeginException exception = errorStatus(methodKey, response);
+		Date retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers()));
+		return new RetryableException(exception.getMessage(), exception, retryAfter);
+	}
+
+	private static PigxFeginException errorStatus(String methodKey, Response response) {
+		try {
+			if (response.body() != null) {
+				Reader reader = response.body().asReader();
+				return new PigxFeginException(R.builder()
+						.msg(IoUtil.read(reader))
+						.code(CommonConstants.FAIL).build());
+			}
+		} catch (IOException ignored) { // NOPMD
+		}
+		String message = format("status %s reading %s", response.status(), methodKey);
+		return new PigxFeginException(message);
+	}
+
+	@Nullable
+	private <T> T firstOrNull(Map<String, Collection<T>> map) {
+		String key = feign.Util.RETRY_AFTER;
+		if (map.containsKey(key) && !map.get(key).isEmpty()) {
+			return map.get(key).iterator().next();
+		}
+		return null;
+	}
+
+	/**
+	 * Decodes a {@link feign.Util#RETRY_AFTER} header into an absolute date, if possible. <br> See <a
+	 * href="https://tools.ietf.org/html/rfc2616#section-14.37">Retry-After format</a>
+	 */
+	static class RetryAfterDecoder {
+
+		static final ConcurrentDateFormat RFC822_FORMAT = ConcurrentDateFormat.of
+				("EEE, dd MMM yyyy HH:mm:ss 'GMT'", US, TimeZone.getTimeZone(ZoneId.of("GMT")));
+		private final ConcurrentDateFormat rfc822Format;
+
+		RetryAfterDecoder() {
+			this(RFC822_FORMAT);
+		}
+
+		RetryAfterDecoder(ConcurrentDateFormat rfc822Format) {
+			this.rfc822Format = checkNotNull(rfc822Format, "rfc822Format");
+		}
+
+		private long currentTimeMillis() {
+			return System.currentTimeMillis();
+		}
+
+		/**
+		 * returns a date that corresponds to the first time a request can be retried.
+		 *
+		 * @param retryAfter String in <a href="https://tools.ietf.org/html/rfc2616#section-14.37">Retry-After format</a>
+		 */
+		@Nullable
+		Date apply(@Nullable String retryAfter) {
+			if (retryAfter == null) {
+				return null;
+			}
+			if (retryAfter.matches(REGEX)) {
+				long deltaMillis = SECONDS.toMillis(Long.parseLong(retryAfter));
+				return new Date(currentTimeMillis() + deltaMillis);
+			}
+			try {
+				return rfc822Format.parse(retryAfter);
+			} catch (ParseException ignored) {
+				return null;
+			}
+		}
+	}
+}

+ 57 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginException.java

@@ -0,0 +1,57 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+package com.pig4cloud.pigx.common.security.feign;
+
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import com.pig4cloud.pigx.common.core.util.R;
+import lombok.Getter;
+
+/**
+ * Fegin 异常
+ *
+ * @author L.cm
+ */
+public class PigxFeginException extends RuntimeException {
+	@Getter
+	private final R result;
+
+	public PigxFeginException(R result) {
+		super(result.getMsg());
+		this.result = result;
+	}
+
+	public PigxFeginException(String message) {
+		super(message);
+		this.result = R.builder()
+				.code(CommonConstants.FAIL)
+				.msg(message).build();
+	}
+
+	/**
+	 * 提高性能
+	 *
+	 * @return {Throwable}
+	 */
+	@Override
+	public Throwable fillInStackTrace() {
+		return this;
+	}
+}

+ 69 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeginFallbackFactory.java

@@ -0,0 +1,69 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+package com.pig4cloud.pigx.common.security.feign;
+
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import com.pig4cloud.pigx.common.core.util.R;
+import feign.hystrix.FallbackFactory;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.cglib.proxy.MethodInterceptor;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * 默认 Fallback,避免写过多fallback类
+ *
+ * @param <T> 泛型标记
+ * @author L.cm
+ */
+@Slf4j
+@NoArgsConstructor
+public final class PigxFeginFallbackFactory<T> implements FallbackFactory<T> {
+	public static final PigxFeginFallbackFactory INSTANCE = new PigxFeginFallbackFactory();
+	private static final ConcurrentMap<Class<?>, Object> FALLBACK_MAP = new ConcurrentHashMap<>();
+
+	@SuppressWarnings("unchecked")
+	public T create(final Class<?> type, final Throwable cause) {
+		// 重写 fegin ErrorDecoder,message 知己为 body 数据,反序列化为 Result
+		final R result = cause instanceof PigxFeginException ?
+				((PigxFeginException) cause).getResult() : R.builder()
+				.code(CommonConstants.FAIL)
+				.msg(cause.getMessage()).build();
+		return (T) FALLBACK_MAP.computeIfAbsent(type, key -> {
+			Enhancer enhancer = new Enhancer();
+			enhancer.setSuperclass(key);
+			enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
+				log.error("Fallback class:[{}] method:[{}] message:[{}]",
+						type.getName(), method.getName(), cause.getMessage());
+				return result;
+			});
+			return enhancer.create();
+		});
+	}
+
+	@Override
+	public T create(Throwable cause) {
+		return null;
+	}
+}

+ 0 - 47
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignClientConfiguration.java

@@ -1,47 +0,0 @@
-/*
- *
- *      Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- *  this list of conditions and the following disclaimer.
- *  Redistributions in binary form must reproduce the above copyright
- *  notice, this list of conditions and the following disclaimer in the
- *  documentation and/or other materials provided with the distribution.
- *  Neither the name of the pig4cloud.com developer nor the names of its
- *  contributors may be used to endorse or promote products derived from
- *  this software without specific prior written permission.
- *  Author: lengleng (wangiegie@gmail.com)
- *
- */
-
-package com.pig4cloud.pigx.common.security.feign;
-
-import feign.RequestInterceptor;
-import lombok.AllArgsConstructor;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.cloud.security.oauth2.client.AccessTokenContextRelay;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.oauth2.client.OAuth2ClientContext;
-import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
-
-/**
- * @author lengleng
- * @date 2018/6/22
- * feign 拦截器传递 header 中oauth token,
- * 使用hystrix 的信号量模式
- */
-@Configuration
-@AllArgsConstructor
-@ConditionalOnProperty("security.oauth2.client.client-id")
-public class PigxFeignClientConfiguration {
-	@Bean
-	public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext,
-															OAuth2ProtectedResourceDetails resource,
-															AccessTokenContextRelay accessTokenContextRelay) {
-		return new PigxFeignClientInterceptor(oAuth2ClientContext, resource,accessTokenContextRelay);
-	}
-}

+ 289 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixFeign.java

@@ -0,0 +1,289 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+package com.pig4cloud.pigx.common.security.feign;
+
+import com.netflix.hystrix.HystrixCommand;
+import feign.*;
+import feign.codec.Decoder;
+import feign.codec.Encoder;
+import feign.codec.ErrorDecoder;
+import feign.hystrix.FallbackFactory;
+import feign.hystrix.HystrixDelegatingContract;
+import feign.hystrix.SetterFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.cloud.openfeign.FeignContext;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * 自定义 Hystrix Feign 实现默认 fallBack
+ *
+ * @author L.cm
+ */
+public class PigxHystrixFeign {
+
+	public static PigxHystrixFeign.Builder builder(FeignContext feignContext) {
+		return new PigxHystrixFeign.Builder(feignContext);
+	}
+
+	public static final class Builder extends Feign.Builder {
+		private Contract contract = new Contract.Default();
+		private SetterFactory setterFactory = new SetterFactory.Default();
+		private final FeignContext feignContext;
+
+		public Builder(FeignContext feignContext) {
+			this.feignContext = feignContext;
+		}
+
+		/**
+		 * Allows you to override hystrix properties such as thread pools and command keys.
+		 */
+		public PigxHystrixFeign.Builder setterFactory(SetterFactory setterFactory) {
+			this.setterFactory = setterFactory;
+			return this;
+		}
+
+		@Override
+		public <T> T target(Target<T> target) {
+			Class<T> targetType = target.type();
+			FeignClient feignClient = AnnotatedElementUtils.getMergedAnnotation(targetType, FeignClient.class);
+			String factoryName = feignClient.name();
+			SetterFactory setterFactoryBean = this.getOptional(factoryName, feignContext, SetterFactory.class);
+			if (setterFactoryBean != null) {
+				this.setterFactory(setterFactoryBean);
+			}
+			Class<?> fallback = feignClient.fallback();
+			if (fallback != void.class) {
+				return targetWithFallback(factoryName, feignContext, target, this, fallback);
+			}
+			Class<?> fallbackFactory = feignClient.fallbackFactory();
+			if (fallbackFactory != void.class) {
+				return targetWithFallbackFactory(factoryName, feignContext, target, this, fallbackFactory);
+			}
+			return build().newInstance(target);
+		}
+
+		@SuppressWarnings("unchecked")
+		private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
+												Target<T> target,
+												PigxHystrixFeign.Builder builder,
+												Class<?> fallbackFactoryClass) {
+			FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>)
+					getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
+		/* We take a sample fallback from the fallback factory to check if it returns a fallback
+		that is compatible with the annotated feign interface. */
+			Object exampleFallback = fallbackFactory.create(new RuntimeException());
+			Assert.notNull(exampleFallback,
+					String.format(
+							"Incompatible fallbackFactory instance for feign client %s. Factory may not produce null!",
+							feignClientName));
+			if (!target.type().isAssignableFrom(exampleFallback.getClass())) {
+				throw new IllegalStateException(
+						String.format(
+								"Incompatible fallbackFactory instance for feign client %s. Factory produces instances of '%s', but should produce instances of '%s'",
+								feignClientName, exampleFallback.getClass(), target.type()));
+			}
+			return builder.target(target, fallbackFactory);
+		}
+
+
+		private <T> T targetWithFallback(String feignClientName, FeignContext context,
+										 Target<T> target,
+										 PigxHystrixFeign.Builder builder, Class<?> fallback) {
+			T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
+			return builder.target(target, fallbackInstance);
+		}
+
+		@SuppressWarnings("unchecked")
+		private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context,
+									 Class<?> beanType, Class<T> targetType) {
+			Object fallbackInstance = context.getInstance(feignClientName, beanType);
+			if (fallbackInstance == null) {
+				throw new IllegalStateException(String.format(
+						"No %s instance of type %s found for feign client %s",
+						fallbackMechanism, beanType, feignClientName));
+			}
+
+			if (!targetType.isAssignableFrom(beanType)) {
+				throw new IllegalStateException(
+						String.format(
+								"Incompatible %s instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
+								fallbackMechanism, beanType, targetType, feignClientName));
+			}
+			return (T) fallbackInstance;
+		}
+
+		@Nullable
+		private <T> T getOptional(String feignClientName, FeignContext context, Class<T> beanType) {
+			return context.getInstance(feignClientName, beanType);
+		}
+
+		/**
+		 * @see #target(Class, String, Object)
+		 */
+		public <T> T target(Target<T> target, @Nullable T fallback) {
+			return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null)
+					.newInstance(target);
+		}
+
+		/**
+		 * @see #target(Class, String, FallbackFactory)
+		 */
+		public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
+			return build(fallbackFactory).newInstance(target);
+		}
+
+		/**
+		 * Like {@link Feign#newInstance(Target)}, except with {@link HystrixCommand
+		 * fallback} support.
+		 *
+		 * <p>Fallbacks are known values, which you return when there's an error invoking an http
+		 * method. For example, you can return a cached result as opposed to raising an error to the
+		 * caller. To use this feature, pass a safe implementation of your target interface as the last
+		 * parameter.
+		 * <p>
+		 * Here's an example:
+		 * <pre>
+		 * {@code
+		 *
+		 * // When dealing with fallbacks, it is less tedious to keep interfaces small.
+		 * interface GitHub {
+		 *   @RequestLine("GET /repos/{owner}/{repo}/contributors")
+		 *   List<String> contributors(@Param("owner") String owner, @Param("repo") String repo);
+		 * }
+		 *
+		 * // This instance will be invoked if there are errors of any kind.
+		 * GitHub fallback = (owner, repo) -> {
+		 *   if (owner.equals("Netflix") && repo.equals("feign")) {
+		 *     return Arrays.asList("stuarthendren"); // inspired this approach!
+		 *   } else {
+		 *     return Collections.emptyList();
+		 *   }
+		 * };
+		 *
+		 * GitHub github = HystrixFeign.builder()
+		 *                             ...
+		 *                             .target(GitHub.class, "https://api.github.com", fallback);
+		 * }</pre>
+		 *
+		 * @see #target(Target, Object)
+		 */
+		public <T> T target(Class<T> apiType, String url, T fallback) {
+			return target(new Target.HardCodedTarget<T>(apiType, url), fallback);
+		}
+
+		/**
+		 * Same as {@link #target(Class, String, T)}, except you can inspect a source exception before
+		 * creating a fallback object.
+		 */
+		public <T> T target(Class<T> apiType, String url, FallbackFactory<? extends T> fallbackFactory) {
+			return target(new Target.HardCodedTarget<T>(apiType, url), fallbackFactory);
+		}
+
+		@Override
+		public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder contract(Contract contract) {
+			this.contract = contract;
+			return this;
+		}
+
+		@Override
+		public Feign build() {
+			return build(null);
+		}
+
+		/**
+		 * Configures components needed for hystrix integration.
+		 */
+		Feign build(@Nullable final FallbackFactory<?> nullableFallbackFactory) {
+			super.invocationHandlerFactory((target, dispatch) ->
+					new PigxHystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory));
+			super.contract(new HystrixDelegatingContract(contract));
+			return super.build();
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder logLevel(Logger.Level logLevel) {
+			return (PigxHystrixFeign.Builder) super.logLevel(logLevel);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder client(Client client) {
+			return (PigxHystrixFeign.Builder) super.client(client);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder retryer(Retryer retryer) {
+			return (PigxHystrixFeign.Builder) super.retryer(retryer);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder logger(Logger logger) {
+			return (PigxHystrixFeign.Builder) super.logger(logger);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder encoder(Encoder encoder) {
+			return (PigxHystrixFeign.Builder) super.encoder(encoder);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder decoder(Decoder decoder) {
+			return (PigxHystrixFeign.Builder) super.decoder(decoder);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) {
+			return (PigxHystrixFeign.Builder) super.mapAndDecode(mapper, decoder);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder decode404() {
+			return (PigxHystrixFeign.Builder) super.decode404();
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder errorDecoder(ErrorDecoder errorDecoder) {
+			return (PigxHystrixFeign.Builder) super.errorDecoder(errorDecoder);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder options(Request.Options options) {
+			return (PigxHystrixFeign.Builder) super.options(options);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder requestInterceptor(RequestInterceptor requestInterceptor) {
+			return (PigxHystrixFeign.Builder) super.requestInterceptor(requestInterceptor);
+		}
+
+		@Override
+		public PigxHystrixFeign.Builder requestInterceptors(Iterable<RequestInterceptor> requestInterceptors) {
+			return (PigxHystrixFeign.Builder) super.requestInterceptors(requestInterceptors);
+		}
+	}
+
+}

+ 218 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixInvocationHandler.java

@@ -0,0 +1,218 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+package com.pig4cloud.pigx.common.security.feign;
+
+import com.netflix.hystrix.HystrixCommand;
+import com.netflix.hystrix.HystrixCommand.Setter;
+import feign.InvocationHandlerFactory.MethodHandler;
+import feign.Target;
+import feign.hystrix.FallbackFactory;
+import feign.hystrix.SetterFactory;
+import org.springframework.lang.Nullable;
+import rx.Completable;
+import rx.Observable;
+import rx.Single;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static feign.Util.checkNotNull;
+
+/**
+ * @author L.cm
+ * <p>
+ * 降级注入
+ */
+public final class PigxHystrixInvocationHandler implements InvocationHandler {
+	private static final String EQUALS = "equals";
+	private static final String HASH_CODE = "hashCode";
+	private static final String TO_STRING = "toString";
+	private final Target<?> target;
+	private final Map<Method, MethodHandler> dispatch;
+	@Nullable
+	private final FallbackFactory<?> fallbackFactory;
+	private final Map<Method, Method> fallbackMethodMap;
+	private final Map<Method, Setter> setterMethodMap;
+
+	PigxHystrixInvocationHandler(
+			Target<?> target, Map<Method,
+			MethodHandler> dispatch,
+			SetterFactory setterFactory,
+			FallbackFactory<?> fallbackFactory) {
+		this.target = checkNotNull(target, "target");
+		this.dispatch = checkNotNull(dispatch, "dispatch");
+		this.fallbackFactory = fallbackFactory;
+		this.fallbackMethodMap = toFallbackMethod(dispatch);
+		this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet());
+	}
+
+	/**
+	 * If the method param of InvocationHandler.invoke is not accessible, i.e in a package-private
+	 * interface, the fallback call in hystrix command will fail cause of access restrictions. But
+	 * methods in dispatch are copied methods. So setting access to dispatch method doesn't take
+	 * effect to the method in InvocationHandler.invoke. Use map to store a copy of method to invoke
+	 * the fallback to bypass this and reducing the count of reflection calls.
+	 *
+	 * @return cached methods map for fallback invoking
+	 */
+	private static Map<Method, Method> toFallbackMethod(Map<Method, MethodHandler> dispatch) {
+		Map<Method, Method> result = new LinkedHashMap<>(dispatch.size());
+		for (Method method : dispatch.keySet()) {
+			method.setAccessible(true);
+			result.put(method, method);
+		}
+		return result;
+	}
+
+	/**
+	 * Process all methods in the target so that appropriate setters are created.
+	 */
+	private static Map<Method, Setter> toSetters(
+			SetterFactory setterFactory, Target<?> target, Set<Method> methods) {
+		Map<Method, Setter> result = new LinkedHashMap<>(methods.size());
+		for (Method method : methods) {
+			method.setAccessible(true);
+			result.put(method, setterFactory.create(target, method));
+		}
+		return result;
+	}
+
+	@Override
+	public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+		// early exit if the invoked method is from java.lang.Object
+		// code is the same as ReflectiveFeign.FeignInvocationHandler
+		if (EQUALS.equals(method.getName())) {
+			try {
+				Object otherHandler = args.length > 0 && args[0] != null
+						? Proxy.getInvocationHandler(args[0]) : null;
+				return equals(otherHandler);
+			} catch (IllegalArgumentException e) {
+				return false;
+			}
+		} else if (HASH_CODE.equals(method.getName())) {
+			return hashCode();
+		} else if (TO_STRING.equals(method.getName())) {
+			return toString();
+		}
+
+		HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {
+			@Override
+			protected Object run() throws Exception {
+				try {
+					return PigxHystrixInvocationHandler.this.dispatch.get(method).invoke(args);
+				} catch (Exception e) {
+					throw e;
+				} catch (Throwable t) {
+					throw (Error) t;
+				}
+			}
+
+			@Override
+			@Nullable
+			@SuppressWarnings("unchecked")
+			protected Object getFallback() {
+				final FallbackFactory<?> localFallbackFactory = fallbackFactory == null ? PigxFeginFallbackFactory.INSTANCE : fallbackFactory;
+				Object fallback;
+				try {
+					if (localFallbackFactory instanceof PigxFeginFallbackFactory) {
+						fallback = ((PigxFeginFallbackFactory) localFallbackFactory).create(target.type(), getExecutionException());
+					} else {
+						fallback = localFallbackFactory.create(getExecutionException());
+					}
+					Object result = fallbackMethodMap.get(method).invoke(fallback, args);
+					if (isReturnsHystrixCommand(method)) {
+						return ((HystrixCommand) result).execute();
+					} else if (isReturnsObservable(method)) {
+						// Create a cold Observable
+						return ((Observable) result).toBlocking().first();
+					} else if (isReturnsSingle(method)) {
+						// Create a cold Observable as a Single
+						return ((Single) result).toObservable().toBlocking().first();
+					} else if (isReturnsCompletable(method)) {
+						((Completable) result).await();
+						return null;
+					} else {
+						return result;
+					}
+				} catch (IllegalAccessException e) {
+					// shouldn't happen as method is public due to being an interface
+					throw new AssertionError(e);
+				} catch (InvocationTargetException e) {
+					// Exceptions on fallback are tossed by Hystrix
+					throw new AssertionError(e.getCause());
+				}
+			}
+		};
+
+		if (isReturnsHystrixCommand(method)) {
+			return hystrixCommand;
+		} else if (isReturnsObservable(method)) {
+			// Create a cold Observable
+			return hystrixCommand.toObservable();
+		} else if (isReturnsSingle(method)) {
+			// Create a cold Observable as a Single
+			return hystrixCommand.toObservable().toSingle();
+		} else if (isReturnsCompletable(method)) {
+			return hystrixCommand.toObservable().toCompletable();
+		}
+		return hystrixCommand.execute();
+	}
+
+	private boolean isReturnsCompletable(Method method) {
+		return Completable.class.isAssignableFrom(method.getReturnType());
+	}
+
+	private boolean isReturnsHystrixCommand(Method method) {
+		return HystrixCommand.class.isAssignableFrom(method.getReturnType());
+	}
+
+	private boolean isReturnsObservable(Method method) {
+		return Observable.class.isAssignableFrom(method.getReturnType());
+	}
+
+	private boolean isReturnsSingle(Method method) {
+		return Single.class.isAssignableFrom(method.getReturnType());
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof PigxHystrixInvocationHandler) {
+			PigxHystrixInvocationHandler other = (PigxHystrixInvocationHandler) obj;
+			return target.equals(other.target);
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return target.hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return target.toString();
+	}
+}

+ 33 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/package-info.java

@@ -0,0 +1,33 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+/**
+ * Hystrix 默认 fallback
+ * <p>
+ * DefaultProperties: https://github.com/Netflix/Hystrix/issues/1446
+ *
+ * @author L.cm
+ */
+@NonNullApi
+@NonNullFields
+package com.pig4cloud.pigx.common.security.feign;
+
+import org.springframework.lang.NonNullApi;
+import org.springframework.lang.NonNullFields;

+ 90 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/ConcurrentDateFormat.java

@@ -0,0 +1,90 @@
+/*
+ * *************************************************************************
+ *   Copyright (c) 2018-2025, dreamlu.net All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: chunmeng.lu (qq596392912@gmail.com)
+ * *************************************************************************
+ */
+
+package com.pig4cloud.pigx.common.security.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Queue;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * 参考tomcat8中的并发DateFormat
+ * <p>
+ * {@link SimpleDateFormat}的线程安全包装器。
+ * 不使用ThreadLocal,创建足够的SimpleDateFormat对象来满足并发性要求。
+ *
+ * @author L.cm
+ */
+public class ConcurrentDateFormat {
+	private final String format;
+	private final Locale locale;
+	private final TimeZone timezone;
+	private final Queue<SimpleDateFormat> queue = new ConcurrentLinkedQueue<>();
+
+	private ConcurrentDateFormat(String format, Locale locale, TimeZone timezone) {
+		this.format = format;
+		this.locale = locale;
+		this.timezone = timezone;
+		SimpleDateFormat initial = createInstance();
+		queue.add(initial);
+	}
+
+	public static ConcurrentDateFormat of(String format) {
+		return new ConcurrentDateFormat(format, Locale.getDefault(), TimeZone.getDefault());
+	}
+
+	public static ConcurrentDateFormat of(String format, TimeZone timezone) {
+		return new ConcurrentDateFormat(format, Locale.getDefault(), timezone);
+	}
+
+	public static ConcurrentDateFormat of(String format, Locale locale, TimeZone timezone) {
+		return new ConcurrentDateFormat(format, locale, timezone);
+	}
+
+	public String format(Date date) {
+		SimpleDateFormat sdf = queue.poll();
+		if (sdf == null) {
+			sdf = createInstance();
+		}
+		String result = sdf.format(date);
+		queue.add(sdf);
+		return result;
+	}
+
+	public Date parse(String source) throws ParseException {
+		SimpleDateFormat sdf = queue.poll();
+		if (sdf == null) {
+			sdf = createInstance();
+		}
+		Date result = sdf.parse(source);
+		queue.add(sdf);
+		return result;
+	}
+
+	private SimpleDateFormat createInstance() {
+		SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
+		sdf.setTimeZone(timezone);
+		return sdf;
+	}
+}

+ 1 - 1
pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories

@@ -1,3 +1,3 @@
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-  com.pig4cloud.pigx.common.security.feign.PigxFeignClientConfiguration,\
+  com.pig4cloud.pigx.common.security.feign.PigxFeginConfiguration,\
   com.pig4cloud.pigx.common.security.service.PigxUserDetailsServiceImpl

+ 1 - 2
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteLogService.java

@@ -20,7 +20,6 @@
 package com.pig4cloud.pigx.admin.api.feign;
 
 import com.pig4cloud.pigx.admin.api.entity.SysLog;
-import com.pig4cloud.pigx.admin.api.feign.factory.RemoteLogServiceFallbackFactory;
 import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
 import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants;
 import com.pig4cloud.pigx.common.core.util.R;
@@ -33,7 +32,7 @@ import org.springframework.web.bind.annotation.RequestHeader;
  * @author lengleng
  * @date 2018/6/28
  */
-@FeignClient(value = ServiceNameConstants.UMPS_SERVICE, fallbackFactory = RemoteLogServiceFallbackFactory.class)
+@FeignClient(value = ServiceNameConstants.UMPS_SERVICE)
 public interface RemoteLogService {
 	/**
 	 * 保存日志

+ 5 - 4
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteTokenService.java

@@ -18,7 +18,6 @@
 package com.pig4cloud.pigx.admin.api.feign;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.pig4cloud.pigx.admin.api.feign.factory.RemoteTokenServiceFallbackFactory;
 import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
 import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants;
 import com.pig4cloud.pigx.common.core.util.R;
@@ -31,23 +30,25 @@ import java.util.Map;
  * @author lengleng
  * @date 2018/9/4
  */
-@FeignClient(value = ServiceNameConstants.AUTH_SERVICE, fallbackFactory = RemoteTokenServiceFallbackFactory.class)
+@FeignClient(value = ServiceNameConstants.AUTH_SERVICE)
 public interface RemoteTokenService {
 	/**
 	 * 分页查询token 信息
 	 *
 	 * @param params 分页参数
+	 * @param from   内部调用标志
 	 * @return page
 	 */
 	@PostMapping("/token/page")
-	R<Page> getTokenPage(@RequestBody Map<String, Object> params,@RequestHeader(SecurityConstants.FROM) String from);
+	R<Page> getTokenPage(@RequestBody Map<String, Object> params, @RequestHeader(SecurityConstants.FROM) String from);
 
 	/**
 	 * 删除token
 	 *
 	 * @param token token
+	 * @param from  内部调用标志
 	 * @return
 	 */
 	@DeleteMapping("/token/{token}")
-	R<Boolean> removeTokenById(@PathVariable("token") String token,@RequestHeader(SecurityConstants.FROM) String from);
+	R<Boolean> removeTokenById(@PathVariable("token") String token, @RequestHeader(SecurityConstants.FROM) String from);
 }

+ 3 - 4
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java

@@ -21,7 +21,6 @@ package com.pig4cloud.pigx.admin.api.feign;
 
 import com.pig4cloud.pigx.admin.api.dto.UserInfo;
 import com.pig4cloud.pigx.admin.api.entity.SysUser;
-import com.pig4cloud.pigx.admin.api.feign.factory.RemoteUserServiceFallbackFactory;
 import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
 import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants;
 import com.pig4cloud.pigx.common.core.util.R;
@@ -36,7 +35,7 @@ import java.util.List;
  * @author lengleng
  * @date 2018/6/22
  */
-@FeignClient(value = ServiceNameConstants.UMPS_SERVICE, fallbackFactory = RemoteUserServiceFallbackFactory.class)
+@FeignClient(value = ServiceNameConstants.UMPS_SERVICE)
 public interface RemoteUserService {
 	/**
 	 * 通过用户名查询用户、角色信息
@@ -47,7 +46,7 @@ public interface RemoteUserService {
 	 */
 	@GetMapping("/user/info/{username}")
 	R<UserInfo> info(@PathVariable("username") String username
-		, @RequestHeader(SecurityConstants.FROM) String from);
+			, @RequestHeader(SecurityConstants.FROM) String from);
 
 	/**
 	 * 通过社交账号或手机号查询用户、角色信息
@@ -58,7 +57,7 @@ public interface RemoteUserService {
 	 */
 	@GetMapping("/social/info/{inStr}")
 	R<UserInfo> social(@PathVariable("inStr") String inStr
-		, @RequestHeader(SecurityConstants.FROM) String from);
+			, @RequestHeader(SecurityConstants.FROM) String from);
 
 	/**
 	 * 查询上级部门的用户信息

+ 0 - 38
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/factory/RemoteLogServiceFallbackFactory.java

@@ -1,38 +0,0 @@
-/*
- *    Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.admin.api.feign.factory;
-
-import com.pig4cloud.pigx.admin.api.feign.RemoteLogService;
-import com.pig4cloud.pigx.admin.api.feign.fallback.RemoteLogServiceFallbackImpl;
-import feign.hystrix.FallbackFactory;
-import org.springframework.stereotype.Component;
-
-/**
- * @author lengleng
- * @date 2018/9/4
- */
-@Component
-public class RemoteLogServiceFallbackFactory implements FallbackFactory<RemoteLogService> {
-
-	@Override
-	public RemoteLogService create(Throwable throwable) {
-		RemoteLogServiceFallbackImpl remoteLogServiceFallback = new RemoteLogServiceFallbackImpl();
-		remoteLogServiceFallback.setCause(throwable);
-		return remoteLogServiceFallback;
-	}
-}

+ 0 - 38
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/factory/RemoteTokenServiceFallbackFactory.java

@@ -1,38 +0,0 @@
-/*
- *    Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.admin.api.feign.factory;
-
-import com.pig4cloud.pigx.admin.api.feign.RemoteTokenService;
-import com.pig4cloud.pigx.admin.api.feign.fallback.RemoteTokenServiceFallbackImpl;
-import feign.hystrix.FallbackFactory;
-import org.springframework.stereotype.Component;
-
-/**
- * @author lengleng
- * @date 2018/9/4
- */
-@Component
-public class RemoteTokenServiceFallbackFactory implements FallbackFactory<RemoteTokenService> {
-
-	@Override
-	public RemoteTokenService create(Throwable throwable) {
-		RemoteTokenServiceFallbackImpl remoteTokenServiceFallback = new RemoteTokenServiceFallbackImpl();
-		remoteTokenServiceFallback.setCause(throwable);
-		return remoteTokenServiceFallback;
-	}
-}

+ 0 - 38
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/factory/RemoteUserServiceFallbackFactory.java

@@ -1,38 +0,0 @@
-/*
- *    Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.admin.api.feign.factory;
-
-import com.pig4cloud.pigx.admin.api.feign.RemoteUserService;
-import com.pig4cloud.pigx.admin.api.feign.fallback.RemoteUserServiceFallbackImpl;
-import feign.hystrix.FallbackFactory;
-import org.springframework.stereotype.Component;
-
-/**
- * @author lengleng
- * @date 2018/9/1
- */
-@Component
-public class RemoteUserServiceFallbackFactory implements FallbackFactory<RemoteUserService> {
-
-	@Override
-	public RemoteUserService create(Throwable throwable) {
-		RemoteUserServiceFallbackImpl remoteUserServiceFallback = new RemoteUserServiceFallbackImpl();
-		remoteUserServiceFallback.setCause(throwable);
-		return remoteUserServiceFallback;
-	}
-}

+ 0 - 51
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteLogServiceFallbackImpl.java

@@ -1,51 +0,0 @@
-/*
- *
- *      Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- *  this list of conditions and the following disclaimer.
- *  Redistributions in binary form must reproduce the above copyright
- *  notice, this list of conditions and the following disclaimer in the
- *  documentation and/or other materials provided with the distribution.
- *  Neither the name of the pig4cloud.com developer nor the names of its
- *  contributors may be used to endorse or promote products derived from
- *  this software without specific prior written permission.
- *  Author: lengleng (wangiegie@gmail.com)
- *
- */
-
-package com.pig4cloud.pigx.admin.api.feign.fallback;
-
-import com.pig4cloud.pigx.admin.api.entity.SysLog;
-import com.pig4cloud.pigx.admin.api.feign.RemoteLogService;
-import com.pig4cloud.pigx.common.core.util.R;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-/**
- * @author lengleng
- * @date 2018/6/26
- */
-@Slf4j
-@Component
-public class RemoteLogServiceFallbackImpl implements RemoteLogService {
-	@Setter
-	private Throwable cause;
-
-	/**
-	 * 保存日志
-	 *
-	 * @param sysLog
-	 * @param from
-	 * @return R
-	 */
-	@Override
-	public R<Boolean> saveLog(SysLog sysLog, String from) {
-		log.error("feign 插入日志失败", cause);
-		return null;
-	}
-}

+ 0 - 65
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteTokenServiceFallbackImpl.java

@@ -1,65 +0,0 @@
-/*
- *    Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.admin.api.feign.fallback;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.pig4cloud.pigx.admin.api.feign.RemoteTokenService;
-import com.pig4cloud.pigx.common.core.util.R;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import java.util.Map;
-
-/**
- * @author lengleng
- * @date 2018/9/4
- * feign token  fallback
- */
-@Slf4j
-@Component
-public class RemoteTokenServiceFallbackImpl implements RemoteTokenService {
-	@Setter
-	private Throwable cause;
-
-	/**
-	 * 分页查询token 信息
-	 *
-	 * @param params 分页参数
-	 * @param from   内部调用标志
-	 * @return page
-	 */
-	@Override
-	public R<Page> getTokenPage(Map<String, Object> params, String from) {
-		log.error("调用认证中心查询token 失败", cause);
-		return null;
-	}
-
-	/**
-	 * 删除token
-	 *
-	 * @param token
-	 * @param from  内部调用标志
-	 * @return
-	 */
-	@Override
-	public R<Boolean> removeTokenById(String token, String from) {
-		log.error("删除token 失败 {}", token, cause);
-		return null;
-	}
-}

+ 0 - 79
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java

@@ -1,79 +0,0 @@
-/*
- *
- *      Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- *  this list of conditions and the following disclaimer.
- *  Redistributions in binary form must reproduce the above copyright
- *  notice, this list of conditions and the following disclaimer in the
- *  documentation and/or other materials provided with the distribution.
- *  Neither the name of the pig4cloud.com developer nor the names of its
- *  contributors may be used to endorse or promote products derived from
- *  this software without specific prior written permission.
- *  Author: lengleng (wangiegie@gmail.com)
- *
- */
-
-package com.pig4cloud.pigx.admin.api.feign.fallback;
-
-import com.pig4cloud.pigx.admin.api.dto.UserInfo;
-import com.pig4cloud.pigx.admin.api.entity.SysUser;
-import com.pig4cloud.pigx.admin.api.feign.RemoteUserService;
-import com.pig4cloud.pigx.common.core.util.R;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-
-/**
- * @author lengleng
- * @date 2018/6/26
- */
-@Slf4j
-@Component
-public class RemoteUserServiceFallbackImpl implements RemoteUserService {
-	@Setter
-	private Throwable cause;
-
-	/**
-	 * 通过用户名查询用户、角色信息
-	 *
-	 * @param username 用户名
-	 * @param from     内外标志
-	 * @return R
-	 */
-	@Override
-	public R<UserInfo> info(String username, String from) {
-		log.error("feign 查询用户信息失败:{}", username, cause);
-		return null;
-	}
-
-	/**
-	 * 通过社交账号查询用户、角色信息
-	 *
-	 * @param inStr appid@code
-	 * @param from  内外标志
-	 * @return
-	 */
-	@Override
-	public R<UserInfo> social(String inStr, String from) {
-		log.error("feign 查询用户信息失败:{}", inStr, cause);
-		return null;
-	}
-
-	/**
-	 * 查询上级部门的用户信息
-	 *
-	 * @param username 用户名
-	 * @return R
-	 */
-	@Override
-	public R<List<SysUser>> ancestorUsers(String username) {
-		log.error("feign 查询用户上级部门用户列失败:{}", username, cause);
-		return null;
-	}
-}

+ 0 - 7
pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring.factories

@@ -1,7 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-  com.pig4cloud.pigx.admin.api.feign.fallback.RemoteUserServiceFallbackImpl,\
-  com.pig4cloud.pigx.admin.api.feign.fallback.RemoteLogServiceFallbackImpl,\
-  com.pig4cloud.pigx.admin.api.feign.fallback.RemoteTokenServiceFallbackImpl,\
-  com.pig4cloud.pigx.admin.api.feign.factory.RemoteUserServiceFallbackFactory,\
-  com.pig4cloud.pigx.admin.api.feign.factory.RemoteLogServiceFallbackFactory,\
-  com.pig4cloud.pigx.admin.api.feign.factory.RemoteTokenServiceFallbackFactory