어떻게 feign 호출 을 사용자 정의 하여 Hstrix 시간 초과,이상 용 단 을 실현 합 니까?
10354 단어 feignhystrix시간 을 초과 하 다녹 여 끊다
spring cloud 프로젝트 에서 feign 통합 hystrix 는 자주 사용 되 지만 최근 에 hystrix 기능 이 강하 다 는 것 을 발 견 했 지만 우리 에 게 는 큰 인재 가 적 게 사용 되 고 있다.
우선 저 는 그의 용 단 작용 만 필요 합 니 다.즉,요청 시간 이 초과 되 고 FeignClient 주석 에 설 치 된 fallback 으로 돌아 가 는 것 입 니 다.차단 작업 이 필요 하지 않 고 다시 시도 할 필요 도 없습니다.Hstrix 가 feign 을 호출 할 때 스 레 드 탱크 격 리 처 리 를 했 습 니 다.이렇게 하면 프로젝트 의 복잡 도 를 증가 시 켰 습 니 다.(스 레 드 탱크 파라미터 설정,스 레 드 가 적 으 면 요청 서 비 스 를 직접 거절 할 수 있 습 니 다.스 레 드 가 많아 지면 관리 해 야 합 니 다...)
현재 feign 이 시간 을 초과 한 후에 직접 이상 을 던 집 니 다.그러면 제때에 녹 았 지만 정상 적 인 프로그램 논 리 는 설정 한 fallback 도 소 용이 없습니다.이 설정 항목 은 Hstrix 에 맞 춰 야 합 니 다.
제 가 필요 한 건 이런 효과 예요.
try{
feign.api();
}catch(){
return fallback();
}
하지만 모든 feign 호출 에 try.catch 를 수 동 으로 추가 하 는 것 은 너무 낮 습 니 다.절단면 과 같은 것 을 쓰 는 것 이 좋 습 니 다.이때 하 이 스 트 릭 스 가 생각 났 어 요.남 의 프레임 워 크 가 이미 만 들 어 졌 으 니 제 가 코드 를 직접 볼 게 요.copy 가 끝 이 잖 아 요.
소스 코드 학습
이틀 전에 발표 한 글 도 관련 이 있 습 니 다feign,hystrix 호출 통합.
이전 분석 키 코드 기반
HystrixInvocationHandler (feign.hystrix)
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
.............
// setterMethodMap hystrixCommand ( 、 .....)
HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {
@Override
protected Object run() throws Exception {
....
HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
....
}
@Override
protected Object getFallback() {
.........
}
};
......
return hystrixCommand.execute();
}
이전 분석 소스 코드 방식 에 따라 어디 가 호출 되 었 는 지 직접 보면 알 수 있 습 니 다.하 이 스 트 릭 스 는 실제 적 으로 자신 이 feign.Builer 라 는 이름 을 feign.hystrix.Hystrix Feign.Builder 는 건축 자 모델 을 사용 하고 생 성 된 유형 은 서 비 스 를 호출 할 때 사 용 됩 니 다.관건 적 인 build()방법 보기
Feign build(final FallbackFactory<?> nullableFallbackFactory) {
super.invocationHandlerFactory(new InvocationHandlerFactory() {
// InvocationHandler aop
@Override public InvocationHandler create(Target target,
Map<Method, MethodHandler> dispatch) {
return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory);
}
});
super.contract(new HystrixDelegatingContract(contract));
return super.build();
}
spring 동적 대리 여기 서 더 이상 말 하지 않 겠 습 니 다.핵심 은 Invocation Handler(jdk 동적 대리 라면)입 니 다.그러면 feign 여기 서도 feign 호출 성명 은 인터페이스 입 니 다.사실은 spring 동적 대리 가 대리 류 를 만 들 었 습 니 다.호출 방법 은 실제 호출 된 것 입 니 다.
java.lang.reflect.InvocationHandler#invoke
방안 구상그러면 우 리 는 Hstrix 의 방식 을 참고 하여 스스로 feign.build 를 실현 하고 Invocation Handler 를 자신의 것 으로 바 꿔 야 한다.
그리고 우리 자신의 Invocation Handler 에서 feign 공식 Invocation Handler 를 호출 하면 됩 니 다.즉,
feign.hystrix.HystrixInvocationHandler#invoke
이 방법 중의
this.dispatch.get(method).invoke(args);
이 코드프로젝트 구체 코드 구현
방안 1
자기 실현
import feign.Feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
/**
* feign
* @author hgf
*/
public class CusFeignBuilder extends Feign.Builder{
public CusFeignBuilder() {
this.invocationHandlerFactory((target, dispatch) -> {
Class<?> type = target.type();
FeignClient annotation = type.getAnnotation(FeignClient.class);
// fallback
Object fallBackObj = null;
if (annotation != null && !annotation.fallback().equals(void.class)) {
try {
fallBackObj = annotation.fallback().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
return new CusFeignInvocationHandler(target, dispatch, fallBackObj);
});
}
}
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.Target;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FeignClient;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.eco.common.utils.Md5Util.logger;
import static feign.Util.checkNotNull;
/**
* feign
*/
@Slf4j
public class CusFeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
private final Object fallbackObj;
private final Map<String, Method> fallbackMethodMap = new ConcurrentHashMap<>();
CusFeignInvocationHandler(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch, Object fallbackObj) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
this.fallbackObj = fallbackObj;
}
public Object feignInvoke(Object proxy, Method method, Object[] args) throws Throwable {
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 ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
return dispatch.get(method).invoke(args);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CusFeignInvocationHandler) {
CusFeignInvocationHandler other = (CusFeignInvocationHandler) obj;
return target.equals(other.target);
}
return false;
}
@Override
public int hashCode() {
return target.hashCode();
}
@Override
public String toString() {
return target.toString();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return feignInvoke(proxy, method, args);
} catch (Throwable throwable) {
String configKey = Feign.configKey(target.type(), method);
logger.error("{} ==> {}", configKey, throwable.getMessage());
try {
return getFallbackReturn(method, args, throwable);
} catch (Throwable e) {
throw throwable;
}
}
}
/**
* {@link FeignClient#fallback()}
* @param method feign
* @param args
* @param throwable
*/
public Object getFallbackReturn(Method method, Object[] args, Throwable throwable) throws Throwable {
if (fallbackObj == null) {
throw new RuntimeException("fallbackObj is null");
}
String configKey = Feign.configKey(target.type(), method);
Method fallbackMethod = fallbackMethodMap.get(configKey);
if (fallbackMethod == null) {
Class<?> declaringClass = method.getDeclaringClass();
FeignClient annotation = declaringClass.getAnnotation(FeignClient.class);
if (annotation == null) {
throw new RuntimeException("FeignClient annotation not found");
}
//
Class<?> fallback = annotation.fallback();
fallbackMethod = fallback.getMethod(method.getName(), method.getParameterTypes());
fallbackMethodMap.put(configKey, fallbackMethod);
}
if (fallbackMethod == null) {
throw new RuntimeException("fallbackMethodMap not found");
}
return fallbackMethod.invoke(fallbackObj, args);
}
}
그리고 spring 용기 에 이 bean 을 등록 하면 됩 니 다.
@Bean
CusFeignBuilder cusFeignBuilder(){
return new CusFeignBuilder();
}
방안 2sentinel 통합,오늘 블 로 그 를 쓰 고 소스 코드 를 뒤 돌아 보 니 발견 되 었 습 니 다.
가입 의존
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
설정 오픈
feign.sentinel.enabled=true
feign 인 터 페 이 스 를 수 동 으로 구현 하여,실체 클래스 를 spring 에 등록 합 니 다.
@Component
public class DeviceApiFallBack implements DeviceApi{
@Override
public ServerResponse<String> login(String appId) {
return ServerResponse.createByErrorMessage(" ");
}
}
사실 코드 를 보면 원리 가 같 고 실현 방식 이 다르다 는 것 을 안다.두 가지 방안 은 모두 괜 찮 습 니 다.방안 은 스스로 코드 양 이 많 고 방안 2 sentinel 이 공식 적 으로 실현 되 지만 의존 도 를 도입 하고 복잡 도 를 증가 해 야 합 니 다.또한 인터페이스 실현 은 spring 에 등록 해 야 합 니 다.
현재 내 가 선택 한 것 은 역시 방안 하나,간단 하 다.
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Spring Cloud에서 Feign에 대한 일반적인 질문 요약1. FeignClient 인터페이스, @GettingMapping 같은 조합 메모는 사용할 수 없음 코드 예: 이쪽 @RequestMapping(value = "/simple/{id}", method = Reque...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.