✨ 添加新特性,feign 自动降级
This commit is contained in:
1 parent
2ba0ab306d
commit
17c23a1c8a
20 files changed
+963
-374
No files matched your search
+68
@@ -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,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,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,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;
|
||||
}
|
||||
}
|
||||
-47
@@ -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,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,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,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,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,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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
/**
|
||||
* 查询上级部门的用户信息
|
||||
|
||||
-38
@@ -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;
|
||||
}
|
||||
}
|
||||
-38
@@ -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;
|
||||
}
|
||||
}
|
||||
-38
@@ -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;
|
||||
}
|
||||
}
|
||||
-51
@@ -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;
|
||||
}
|
||||
}
|
||||
-65
@@ -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;
|
||||
}
|
||||
}
|
||||
-79
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in new issue
Block a user