From 35e0c6327f5045b4e75ecd3701ecdf2f9d1b93c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= Date: Sun, 24 Feb 2019 19:37:09 +0800 Subject: [PATCH] =?UTF-8?q?:recycle:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=8C=E9=87=8D=E6=9E=84=E8=87=AA=E5=8A=A8=E9=99=8D?= =?UTF-8?q?=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pigx-common/pigx-common-security/pom.xml | 23 +- .../security/component/PermissionService.java | 24 +- ...urceServerTokenRelayAutoConfiguration.java | 17 ++ .../feign/PigxFeignConfiguration.java | 29 +- .../security/feign/PigxFeignErrorDecoder.java | 129 -------- .../security/feign/PigxFeignException.java | 57 ---- .../feign/PigxFeignFallbackFactory.java | 57 ---- .../feign/PigxFeignFallbackMethod.java | 38 --- .../security/feign/PigxHystrixFeign.java | 289 ------------------ .../feign/PigxHystrixInvocationHandler.java | 217 ------------- .../security/util/ConcurrentDateFormat.java | 11 +- .../common/security/util/SecurityUtils.java | 24 +- .../{feign => util}/package-info.java | 13 +- .../cloud/openfeign/PigxFallbackFactory.java | 45 +++ .../cloud/openfeign/PigxFeignFallback.java | 81 +++++ ...PigxHystrixFeignTargeterConfiguration.java | 42 +++ .../cloud/openfeign/PigxHystrixTargeter.java | 96 ++++++ .../main/resources/META-INF/spring.factories | 2 +- 18 files changed, 328 insertions(+), 866 deletions(-) delete mode 100644 pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignErrorDecoder.java delete mode 100644 pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignException.java delete mode 100644 pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackFactory.java delete mode 100644 pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackMethod.java delete mode 100644 pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixFeign.java delete mode 100644 pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixInvocationHandler.java rename pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/{feign => util}/package-info.java (68%) create mode 100644 pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFallbackFactory.java create mode 100644 pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java create mode 100644 pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixFeignTargeterConfiguration.java create mode 100644 pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixTargeter.java diff --git a/pigx-common/pigx-common-security/pom.xml b/pigx-common/pigx-common-security/pom.xml index 550123808..8a8f72089 100644 --- a/pigx-common/pigx-common-security/pom.xml +++ b/pigx-common/pigx-common-security/pom.xml @@ -1,20 +1,19 @@ diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java index 4235477b3..b16fcb31a 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java @@ -1,20 +1,18 @@ /* + * Copyright (c) 2018-2025, lengleng All rights reserved. * - * 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: + * 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) - * + * 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.component; diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerTokenRelayAutoConfiguration.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerTokenRelayAutoConfiguration.java index ca8a2aac0..5615afaa9 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerTokenRelayAutoConfiguration.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerTokenRelayAutoConfiguration.java @@ -1,3 +1,20 @@ +/* + * 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.component; import org.springframework.boot.autoconfigure.AutoConfigureAfter; diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignConfiguration.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignConfiguration.java index 38b3208bb..55069b710 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignConfiguration.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignConfiguration.java @@ -1,37 +1,29 @@ /* - * ************************************************************************* - * Copyright (c) 2018-2025, dreamlu.net All rights reserved. + * 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: + * 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 + * 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: chunmeng.lu (qq596392912@gmail.com) - * ************************************************************************* + * Author: lengleng (wangiegie@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; @@ -52,17 +44,4 @@ public class PigxFeignConfiguration { 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 PigxFeignErrorDecoder()); - } - } - } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignErrorDecoder.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignErrorDecoder.java deleted file mode 100644 index 70a4175b6..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignErrorDecoder.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * ************************************************************************* - * 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 PigxFeignErrorDecoder extends ErrorDecoder.Default { - private final RetryAfterDecoder retryAfterDecoder = new RetryAfterDecoder(); - private static final String REGEX = "^[0-9]+$"; - - - @Override - public Exception decode(String methodKey, Response response) { - PigxFeignException exception = errorStatus(methodKey, response); - Date retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers())); - return new RetryableException(exception.getMessage(), response.request().httpMethod(), exception, retryAfter); - } - - private static PigxFeignException errorStatus(String methodKey, Response response) { - try { - if (response.body() != null) { - Reader reader = response.body().asReader(); - return new PigxFeignException(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 PigxFeignException(message); - } - - @Nullable - private T firstOrNull(Map> 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.
See Retry-After format - */ - 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 Retry-After format - */ - @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; - } - } - } -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignException.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignException.java deleted file mode 100644 index 352d023c1..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignException.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * ************************************************************************* - * 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 PigxFeignException extends RuntimeException { - @Getter - private final R result; - - public PigxFeignException(R result) { - super(result.getMsg()); - this.result = result; - } - - public PigxFeignException(String message) { - super(message); - this.result = R.builder() - .code(CommonConstants.FAIL) - .msg(message).build(); - } - - /** - * 提高性能 - * - * @return {Throwable} - */ - @Override - public Throwable fillInStackTrace() { - return this; - } -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackFactory.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackFactory.java deleted file mode 100644 index a769341b4..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * ************************************************************************* - * 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 feign.hystrix.FallbackFactory; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.cglib.proxy.Enhancer; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * 默认 Fallback,避免写过多fallback类 - * - * @param 泛型标记 - * @author L.cm - */ -@Slf4j -@NoArgsConstructor -public final class PigxFeignFallbackFactory implements FallbackFactory { - public static final PigxFeignFallbackFactory INSTANCE = new PigxFeignFallbackFactory(); - private static final ConcurrentMap, Object> FALLBACK_MAP = new ConcurrentHashMap<>(); - - @SuppressWarnings("unchecked") - public T create(final Class type, final Throwable cause) { - return (T) FALLBACK_MAP.computeIfAbsent(type, key -> { - Enhancer enhancer = new Enhancer(); - enhancer.setSuperclass(key); - enhancer.setCallback(new PigxFeignFallbackMethod(type, cause)); - return enhancer.create(); - }); - } - - @Override - public T create(Throwable cause) { - return null; - } -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackMethod.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackMethod.java deleted file mode 100644 index 342c3bcf8..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxFeignFallbackMethod.java +++ /dev/null @@ -1,38 +0,0 @@ -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.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.cglib.proxy.MethodInterceptor; -import org.springframework.cglib.proxy.MethodProxy; -import org.springframework.lang.Nullable; - -import java.lang.reflect.Method; - -/** - * @author lengleng - * @date 2019-01-22 - */ -@Slf4j -@AllArgsConstructor -public class PigxFeignFallbackMethod implements MethodInterceptor { - private Class type; - private Throwable cause; - - @Nullable - @Override - public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) { - log.error("Fallback class:[{}] method:[{}] message:[{}]", - type.getName(), method.getName(), cause.getMessage()); - - if (R.class == method.getReturnType()) { - final R result = cause instanceof PigxFeignException ? - ((PigxFeignException) cause).getResult() : R.builder() - .code(CommonConstants.FAIL) - .msg(cause.getMessage()).build(); - return result; - } - return null; - } -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixFeign.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixFeign.java deleted file mode 100644 index 640e1624c..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixFeign.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * ************************************************************************* - * 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 target(Target target) { - Class 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 targetWithFallbackFactory(String feignClientName, FeignContext context, - Target target, - PigxHystrixFeign.Builder builder, - Class fallbackFactoryClass) { - FallbackFactory fallbackFactory = (FallbackFactory) - 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 targetWithFallback(String feignClientName, FeignContext context, - Target target, - PigxHystrixFeign.Builder builder, Class fallback) { - T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type()); - return builder.target(target, fallbackInstance); - } - - @SuppressWarnings("unchecked") - private T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context, - Class beanType, Class 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 getOptional(String feignClientName, FeignContext context, Class beanType) { - return context.getInstance(feignClientName, beanType); - } - - /** - * @see #target(Class, String, Object) - */ - public T target(Target target, @Nullable T fallback) { - return build(fallback != null ? new FallbackFactory.Default(fallback) : null) - .newInstance(target); - } - - /** - * @see #target(Class, String, FallbackFactory) - */ - public T target(Target target, FallbackFactory fallbackFactory) { - return build(fallbackFactory).newInstance(target); - } - - /** - * Like {@link Feign#newInstance(Target)}, except with {@link HystrixCommand - * fallback} support. - * - *

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. - *

- * Here's an example: - *

-		 * {@code
-		 *
-		 * // When dealing with fallbacks, it is less tedious to keep interfaces small.
-		 * interface GitHub {
-		 *   @RequestLine("GET /repos/{owner}/{repo}/contributors")
-		 *   List 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);
-		 * }
- * - * @see #target(Target, Object) - */ - public T target(Class apiType, String url, T fallback) { - return target(new Target.HardCodedTarget(apiType, url), fallback); - } - - /** - * Same as {@link #target(Class, String, T)}, except you can inspect a source exception before - * creating a fallback object. - */ - public T target(Class apiType, String url, FallbackFactory fallbackFactory) { - return target(new Target.HardCodedTarget(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 requestInterceptors) { - return (PigxHystrixFeign.Builder) super.requestInterceptors(requestInterceptors); - } - } - -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixInvocationHandler.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixInvocationHandler.java deleted file mode 100644 index 17ed399ac..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/PigxHystrixInvocationHandler.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * ************************************************************************* - * 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 - *

- * 降级注入 - */ -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 dispatch; - @Nullable - private final FallbackFactory fallbackFactory; - private final Map fallbackMethodMap; - private final Map setterMethodMap; - - PigxHystrixInvocationHandler( - Target target, Map 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 toFallbackMethod(Map dispatch) { - Map 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 toSetters( - SetterFactory setterFactory, Target target, Set methods) { - Map 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 hystrixCommand = new HystrixCommand(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() { - Object fallback; - try { - if (fallbackFactory == null) { - fallback = PigxFeignFallbackFactory.INSTANCE.create(target.type(), getExecutionException()); - } else { - fallback = fallbackFactory.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(); - } -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/ConcurrentDateFormat.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/ConcurrentDateFormat.java index e0416ca46..b0063b674 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/ConcurrentDateFormat.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/ConcurrentDateFormat.java @@ -1,21 +1,18 @@ /* - * ************************************************************************* - * Copyright (c) 2018-2025, dreamlu.net All rights reserved. + * 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: + * 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 + * 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: chunmeng.lu (qq596392912@gmail.com) - * ************************************************************************* + * Author: lengleng (wangiegie@gmail.com) */ package com.pig4cloud.pigx.common.security.util; diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java index e19b2793d..bf6b55fa9 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java @@ -1,20 +1,18 @@ /* + * Copyright (c) 2018-2025, lengleng All rights reserved. * - * 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: + * 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) - * + * 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.util; diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/package-info.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/package-info.java similarity index 68% rename from pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/package-info.java rename to pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/package-info.java index ab9363e5e..62490d11e 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/feign/package-info.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/package-info.java @@ -1,21 +1,18 @@ /* - * ************************************************************************* - * Copyright (c) 2018-2025, dreamlu.net All rights reserved. + * 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: + * 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 + * 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: chunmeng.lu (qq596392912@gmail.com) - * ************************************************************************* + * Author: lengleng (wangiegie@gmail.com) */ /** @@ -27,7 +24,7 @@ */ @NonNullApi @NonNullFields -package com.pig4cloud.pigx.common.security.feign; +package com.pig4cloud.pigx.common.security.util; import org.springframework.lang.NonNullApi; import org.springframework.lang.NonNullFields; diff --git a/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFallbackFactory.java b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFallbackFactory.java new file mode 100644 index 000000000..1cecb1537 --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFallbackFactory.java @@ -0,0 +1,45 @@ +/* + * 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 org.springframework.cloud.openfeign; + +import feign.Target; +import feign.hystrix.FallbackFactory; +import lombok.AllArgsConstructor; +import org.springframework.cglib.proxy.Enhancer; + +/** + * @author 冷冷 + *

+ * 默认 Fallback,避免写过多fallback类 + */ +@AllArgsConstructor +public class PigxFallbackFactory implements FallbackFactory { + private final Target target; + + @Override + @SuppressWarnings("unchecked") + public T create(Throwable cause) { + final Class targetType = target.type(); + final String targetName = target.name(); + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(targetType); + enhancer.setUseCache(true); + enhancer.setCallback(new PigxFeignFallback<>(targetType, targetName, cause)); + return (T) enhancer.create(); + } +} diff --git a/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java new file mode 100644 index 000000000..c5a5a9201 --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java @@ -0,0 +1,81 @@ +/* + * 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 org.springframework.cloud.openfeign; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import com.pig4cloud.pigx.common.core.util.R; +import feign.FeignException; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cglib.proxy.MethodInterceptor; +import org.springframework.cglib.proxy.MethodProxy; +import org.springframework.lang.Nullable; + +import java.lang.reflect.Method; +import java.util.Objects; + +/** + * @author lengleng + *

+ * fallBack 代理处理 + */ +@Slf4j +@AllArgsConstructor +public class PigxFeignFallback implements MethodInterceptor { + private final Class targetType; + private final String targetName; + private final Throwable cause; + + @Nullable + @Override + public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { + String errorMessage = cause.getMessage(); + log.error("MicaFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, errorMessage); + Class returnType = method.getReturnType(); + if (R.class != returnType) { + return null; + } + FeignException exception = (FeignException) cause; + + byte[] content = exception.content(); + + String str = StrUtil.str(content, CharsetUtil.UTF_8); + + return R.builder().code(CommonConstants.FAIL) + .msg(str).build(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PigxFeignFallback that = (PigxFeignFallback) o; + return targetType.equals(that.targetType); + } + + @Override + public int hashCode() { + return Objects.hash(targetType); + } +} diff --git a/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixFeignTargeterConfiguration.java b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixFeignTargeterConfiguration.java new file mode 100644 index 000000000..2a289d9ec --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixFeignTargeterConfiguration.java @@ -0,0 +1,42 @@ +/* + * 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 org.springframework.cloud.openfeign; + +import feign.hystrix.HystrixFeign; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +/** + * @author lengleng + *

+ * HystrixFeignTargeter 配置 + */ +@Configuration +@ConditionalOnClass(HystrixFeign.class) +@ConditionalOnProperty("feign.hystrix.enabled") +public class PigxHystrixFeignTargeterConfiguration { + + @Bean + @Primary + public Targeter micaFeignTargeter() { + return new PigxHystrixTargeter(); + } +} diff --git a/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixTargeter.java b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixTargeter.java new file mode 100644 index 000000000..fa492f786 --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxHystrixTargeter.java @@ -0,0 +1,96 @@ +/* + * 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 org.springframework.cloud.openfeign; + +import feign.Feign; +import feign.Target; +import feign.hystrix.FallbackFactory; +import feign.hystrix.HystrixFeign; +import feign.hystrix.SetterFactory; +import org.springframework.lang.Nullable; + +/** + * @author lengleng + *

+ * 注入默认的 fallbackFactory + */ +@SuppressWarnings("unchecked") +class PigxHystrixTargeter implements Targeter { + + @Override + public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, + Target.HardCodedTarget target) { + if (!(feign instanceof HystrixFeign.Builder)) { + return feign.target(target); + } + HystrixFeign.Builder builder = (HystrixFeign.Builder) feign; + SetterFactory setterFactory = getOptional(factory.getName(), context, SetterFactory.class); + if (setterFactory != null) { + builder.setterFactory(setterFactory); + } + Class fallback = factory.getFallback(); + if (fallback != void.class) { + return targetWithFallback(factory.getName(), context, target, builder, fallback); + } + Class fallbackFactory = factory.getFallbackFactory(); + if (fallbackFactory != void.class) { + return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory); + } + + PigxFallbackFactory micaFallbackFactory = new PigxFallbackFactory(target); + return (T) builder.target(target, micaFallbackFactory); + } + + private T targetWithFallbackFactory(String feignClientName, FeignContext context, + Target.HardCodedTarget target, + HystrixFeign.Builder builder, + Class fallbackFactoryClass) { + FallbackFactory fallbackFactory = (FallbackFactory) + getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class); + return builder.target(target, fallbackFactory); + } + + + private T targetWithFallback(String feignClientName, FeignContext context, + Target.HardCodedTarget target, + HystrixFeign.Builder builder, Class fallback) { + T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type()); + return builder.target(target, fallbackInstance); + } + + private T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context, Class beanType, + Class targetType) { + Object fallbackInstance = context.getInstance(feignClientName, beanType); + if (fallbackInstance == null) { + throw new IllegalStateException(String.format("No " + fallbackMechanism + + " instance of type %s found for feign client %s", beanType, feignClientName)); + } + + if (!targetType.isAssignableFrom(beanType)) { + throw new IllegalStateException(String.format( + "Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of " + + "type %s is not assignable to %s for feign client %s", beanType, targetType, feignClientName)); + } + return (T) fallbackInstance; + } + + @Nullable + private T getOptional(String feignClientName, FeignContext context, Class beanType) { + return context.getInstance(feignClientName, beanType); + } +} diff --git a/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories b/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories index a1d90172a..23129a178 100644 --- a/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories +++ b/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories @@ -1,4 +1,4 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.springframework.cloud.openfeign.PigxHystrixFeignTargeterConfiguration,\ com.pig4cloud.pigx.common.security.component.GlobalExceptionHandlerResolver,\ - com.pig4cloud.pigx.common.security.feign.PigxFeignConfiguration,\ com.pig4cloud.pigx.common.security.service.PigxUserDetailsServiceImpl