parent
f6829e726e
commit
63c641848c
@ -0,0 +1,80 @@
|
|||||||
|
package com.tencent.cloud.polaris.circuitbreaker.feign;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
|
||||||
|
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
|
||||||
|
import feign.Request;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import feign.Response;
|
||||||
|
import feign.codec.Decoder;
|
||||||
|
|
||||||
|
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||||
|
|
||||||
|
public class PolarisCircuitBreakerFallbackFactory implements FallbackFactory {
|
||||||
|
|
||||||
|
private final Decoder decoder;
|
||||||
|
|
||||||
|
public PolarisCircuitBreakerFallbackFactory(Decoder decoder) {
|
||||||
|
this.decoder = decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object create(Throwable t) {
|
||||||
|
return new DefaultFallback(t, decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DefaultFallback {
|
||||||
|
|
||||||
|
private final Throwable t;
|
||||||
|
|
||||||
|
private final Decoder decoder;
|
||||||
|
|
||||||
|
public DefaultFallback(Throwable t, Decoder decoder) {
|
||||||
|
this.t = t;
|
||||||
|
this.decoder = decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object fallback(Method method) {
|
||||||
|
if (t instanceof CallAbortedException) {
|
||||||
|
CircuitBreakerStatus.FallbackInfo fallbackInfo = ((CallAbortedException) t).getFallbackInfo();
|
||||||
|
if (fallbackInfo != null) {
|
||||||
|
Response.Builder responseBuilder = Response.builder()
|
||||||
|
.status(fallbackInfo.getCode());
|
||||||
|
if (fallbackInfo.getHeaders() != null) {
|
||||||
|
Map<String, Collection<String>> headers = new HashMap<>();
|
||||||
|
fallbackInfo.getHeaders().forEach((k, v) -> {
|
||||||
|
if (headers.containsKey(k)) {
|
||||||
|
headers.get(k).add(v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
headers.put(k, new HashSet<>(Collections.singleton(v)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
responseBuilder.headers(headers);
|
||||||
|
}
|
||||||
|
if (fallbackInfo.getBody() != null) {
|
||||||
|
responseBuilder.body(fallbackInfo.getBody(), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
// Feign Response need a nonnull Request, which is not important in fallback response, so we create a fake one
|
||||||
|
Request request = Request.create(Request.HttpMethod.GET, "/", new HashMap<>(), Request.Body.empty(), new RequestTemplate());
|
||||||
|
responseBuilder.request(request);
|
||||||
|
try (Response response = responseBuilder.build()) {
|
||||||
|
return decoder.decode(response, method.getGenericReturnType());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package com.tencent.cloud.polaris.circuitbreaker.feign;
|
||||||
|
|
||||||
|
import feign.Feign;
|
||||||
|
import feign.Target;
|
||||||
|
|
||||||
|
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
||||||
|
import org.springframework.cloud.openfeign.CircuitBreakerNameResolver;
|
||||||
|
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||||
|
|
||||||
|
public class PolarisFeignCircuitBreaker {
|
||||||
|
|
||||||
|
private PolarisFeignCircuitBreaker() {
|
||||||
|
throw new IllegalStateException("Don't instantiate a utility class");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return builder for Feign CircuitBreaker integration
|
||||||
|
*/
|
||||||
|
public static PolarisFeignCircuitBreaker.Builder builder(Feign.Builder delegateBuilder) {
|
||||||
|
return new PolarisFeignCircuitBreaker.Builder(delegateBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for Feign CircuitBreaker integration.
|
||||||
|
*/
|
||||||
|
public static final class Builder extends Feign.Builder {
|
||||||
|
|
||||||
|
private final Feign.Builder delegateBuilder;
|
||||||
|
|
||||||
|
public Builder(Feign.Builder delegateBuilder) {
|
||||||
|
this.delegateBuilder = delegateBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CircuitBreakerFactory circuitBreakerFactory;
|
||||||
|
|
||||||
|
private String feignClientName;
|
||||||
|
|
||||||
|
private CircuitBreakerNameResolver circuitBreakerNameResolver;
|
||||||
|
|
||||||
|
public PolarisFeignCircuitBreaker.Builder circuitBreakerFactory(CircuitBreakerFactory circuitBreakerFactory) {
|
||||||
|
this.circuitBreakerFactory = circuitBreakerFactory;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolarisFeignCircuitBreaker.Builder feignClientName(String feignClientName) {
|
||||||
|
this.feignClientName = feignClientName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolarisFeignCircuitBreaker.Builder circuitBreakerNameResolver(CircuitBreakerNameResolver circuitBreakerNameResolver) {
|
||||||
|
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T target(Target<T> target, T fallback) {
|
||||||
|
return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null).newInstance(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
|
||||||
|
return build(fallbackFactory).newInstance(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T target(Target<T> target) {
|
||||||
|
return build(null).newInstance(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Feign build(final FallbackFactory<?> nullableFallbackFactory) {
|
||||||
|
delegateBuilder.invocationHandlerFactory((target, dispatch) -> new PolarisFeignCircuitBreakerInvocationHandler(
|
||||||
|
circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory, circuitBreakerNameResolver, this.decoder));
|
||||||
|
return delegateBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,178 @@
|
|||||||
|
package com.tencent.cloud.polaris.circuitbreaker.feign;
|
||||||
|
|
||||||
|
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.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import feign.InvocationHandlerFactory;
|
||||||
|
import feign.Target;
|
||||||
|
import feign.codec.Decoder;
|
||||||
|
|
||||||
|
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
|
||||||
|
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
||||||
|
import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException;
|
||||||
|
import org.springframework.cloud.openfeign.CircuitBreakerNameResolver;
|
||||||
|
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
|
||||||
|
import static feign.Util.checkNotNull;
|
||||||
|
|
||||||
|
public class PolarisFeignCircuitBreakerInvocationHandler implements InvocationHandler {
|
||||||
|
|
||||||
|
private final CircuitBreakerFactory factory;
|
||||||
|
|
||||||
|
private final String feignClientName;
|
||||||
|
|
||||||
|
private final Target<?> target;
|
||||||
|
|
||||||
|
private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
|
||||||
|
|
||||||
|
private final FallbackFactory<?> nullableFallbackFactory;
|
||||||
|
|
||||||
|
private final Map<Method, Method> fallbackMethodMap;
|
||||||
|
|
||||||
|
private final CircuitBreakerNameResolver circuitBreakerNameResolver;
|
||||||
|
|
||||||
|
private final Decoder decoder;
|
||||||
|
|
||||||
|
public PolarisFeignCircuitBreakerInvocationHandler(CircuitBreakerFactory factory, String feignClientName, Target<?> target,
|
||||||
|
Map<Method, InvocationHandlerFactory.MethodHandler> dispatch, FallbackFactory<?> nullableFallbackFactory,
|
||||||
|
CircuitBreakerNameResolver circuitBreakerNameResolver, Decoder decoder) {
|
||||||
|
this.factory = factory;
|
||||||
|
this.feignClientName = feignClientName;
|
||||||
|
this.target = checkNotNull(target, "target");
|
||||||
|
this.dispatch = checkNotNull(dispatch, "dispatch");
|
||||||
|
this.fallbackMethodMap = toFallbackMethod(dispatch);
|
||||||
|
this.nullableFallbackFactory = nullableFallbackFactory;
|
||||||
|
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
|
||||||
|
this.decoder = decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 ("hashCode".equals(method.getName())) {
|
||||||
|
return hashCode();
|
||||||
|
}
|
||||||
|
else if ("toString".equals(method.getName())) {
|
||||||
|
return toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method);
|
||||||
|
CircuitBreaker circuitBreaker = factory.create(circuitName);
|
||||||
|
Supplier<Object> supplier = asSupplier(method, args);
|
||||||
|
Function<Throwable, Object> fallbackFunction;
|
||||||
|
if (this.nullableFallbackFactory != null) {
|
||||||
|
fallbackFunction = throwable -> {
|
||||||
|
Object fallback = this.nullableFallbackFactory.create(throwable);
|
||||||
|
try {
|
||||||
|
return this.fallbackMethodMap.get(method).invoke(fallback, args);
|
||||||
|
}
|
||||||
|
catch (Exception exception) {
|
||||||
|
unwrapAndRethrow(exception);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fallbackFunction = throwable -> {
|
||||||
|
PolarisCircuitBreakerFallbackFactory.DefaultFallback fallback =
|
||||||
|
(PolarisCircuitBreakerFallbackFactory.DefaultFallback) new PolarisCircuitBreakerFallbackFactory(this.decoder).create(throwable);
|
||||||
|
return fallback.fallback(method);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return circuitBreaker.run(supplier, fallbackFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unwrapAndRethrow(Exception exception) {
|
||||||
|
if (exception instanceof InvocationTargetException || exception instanceof NoFallbackAvailableException) {
|
||||||
|
Throwable underlyingException = exception.getCause();
|
||||||
|
if (underlyingException instanceof RuntimeException) {
|
||||||
|
throw (RuntimeException) underlyingException;
|
||||||
|
}
|
||||||
|
if (underlyingException != null) {
|
||||||
|
throw new IllegalStateException(underlyingException);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Supplier<Object> asSupplier(final Method method, final Object[] args) {
|
||||||
|
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||||
|
final Thread caller = Thread.currentThread();
|
||||||
|
return () -> {
|
||||||
|
boolean isAsync = caller != Thread.currentThread();
|
||||||
|
try {
|
||||||
|
if (isAsync) {
|
||||||
|
RequestContextHolder.setRequestAttributes(requestAttributes);
|
||||||
|
}
|
||||||
|
return dispatch.get(method).invoke(args);
|
||||||
|
}
|
||||||
|
catch (RuntimeException throwable) {
|
||||||
|
throw throwable;
|
||||||
|
}
|
||||||
|
catch (Throwable throwable) {
|
||||||
|
throw new RuntimeException(throwable);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (isAsync) {
|
||||||
|
RequestContextHolder.resetRequestAttributes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the method param of {@link InvocationHandler#invoke(Object, Method, Object[])}
|
||||||
|
* is not accessible, i.e in a package-private interface, the fallback call will 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
|
||||||
|
*/
|
||||||
|
static Map<Method, Method> toFallbackMethod(Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
|
||||||
|
Map<Method, Method> result = new LinkedHashMap<>();
|
||||||
|
for (Method method : dispatch.keySet()) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
result.put(method, method);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof PolarisFeignCircuitBreakerInvocationHandler) {
|
||||||
|
PolarisFeignCircuitBreakerInvocationHandler other = (PolarisFeignCircuitBreakerInvocationHandler) obj;
|
||||||
|
return this.target.equals(other.target);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return this.target.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.target.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.tencent.cloud.polaris.circuitbreaker.feign;
|
||||||
|
|
||||||
|
import feign.Feign;
|
||||||
|
import feign.Target;
|
||||||
|
|
||||||
|
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
||||||
|
import org.springframework.cloud.openfeign.CircuitBreakerNameResolver;
|
||||||
|
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||||
|
import org.springframework.cloud.openfeign.FeignCircuitBreaker;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClientFactoryBean;
|
||||||
|
import org.springframework.cloud.openfeign.FeignContext;
|
||||||
|
import org.springframework.cloud.openfeign.Targeter;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
public class PolarisFeignCircuitBreakerTargeter implements Targeter {
|
||||||
|
|
||||||
|
private final CircuitBreakerFactory circuitBreakerFactory;
|
||||||
|
|
||||||
|
private final CircuitBreakerNameResolver circuitBreakerNameResolver;
|
||||||
|
|
||||||
|
public PolarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, CircuitBreakerNameResolver circuitBreakerNameResolver) {
|
||||||
|
this.circuitBreakerFactory = circuitBreakerFactory;
|
||||||
|
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||||
|
Target.HardCodedTarget<T> target) {
|
||||||
|
if (!(feign instanceof FeignCircuitBreaker.Builder)) {
|
||||||
|
return feign.target(target);
|
||||||
|
}
|
||||||
|
PolarisFeignCircuitBreaker.Builder builder = PolarisFeignCircuitBreaker.builder(feign);
|
||||||
|
String name = !StringUtils.hasText(factory.getContextId()) ? factory.getName() : factory.getContextId();
|
||||||
|
Class<?> fallback = factory.getFallback();
|
||||||
|
if (fallback != void.class) {
|
||||||
|
return targetWithFallback(name, context, target, builder, fallback);
|
||||||
|
}
|
||||||
|
Class<?> fallbackFactory = factory.getFallbackFactory();
|
||||||
|
if (fallbackFactory != void.class) {
|
||||||
|
return targetWithFallbackFactory(name, context, target, builder, fallbackFactory);
|
||||||
|
}
|
||||||
|
return builder(name, builder).target(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
|
||||||
|
Target.HardCodedTarget<T> target, PolarisFeignCircuitBreaker.Builder builder, Class<?> fallbackFactoryClass) {
|
||||||
|
FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext("fallbackFactory",
|
||||||
|
feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
|
||||||
|
return builder(feignClientName, builder).target(target, fallbackFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget<T> target,
|
||||||
|
PolarisFeignCircuitBreaker.Builder builder, Class<?> fallback) {
|
||||||
|
T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
|
||||||
|
return builder(feignClientName, builder).target(target, fallbackInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 " + 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PolarisFeignCircuitBreaker.Builder builder(String feignClientName, PolarisFeignCircuitBreaker.Builder builder) {
|
||||||
|
return builder
|
||||||
|
.circuitBreakerFactory(circuitBreakerFactory)
|
||||||
|
.feignClientName(feignClientName)
|
||||||
|
.circuitBreakerNameResolver(circuitBreakerNameResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,34 +1,34 @@
|
|||||||
///*
|
/*
|
||||||
// * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
// *
|
*
|
||||||
// * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
// *
|
*
|
||||||
// * Licensed under the BSD 3-Clause License (the "License");
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
// * you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
// * You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
// *
|
*
|
||||||
// * https://opensource.org/licenses/BSD-3-Clause
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
// *
|
*
|
||||||
// * Unless required by applicable law or agreed to in writing, software distributed
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
// * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
// * CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// * specific language governing permissions and limitations under the License.
|
* specific language governing permissions and limitations under the License.
|
||||||
// */
|
*/
|
||||||
//
|
|
||||||
//package com.tencent.cloud.polaris.circuitbreaker.feign.example;
|
package com.tencent.cloud.polaris.circuitbreaker.feign.example;
|
||||||
//
|
|
||||||
//import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
//
|
|
||||||
///**
|
/**
|
||||||
// * Circuit breaker example callee fallback.
|
* Circuit breaker example callee fallback.
|
||||||
// *
|
*
|
||||||
// * @author sean yu
|
* @author sean yu
|
||||||
// */
|
*/
|
||||||
//@Component
|
@Component
|
||||||
//public class ProviderBFallback implements ProviderB {
|
public class ProviderBFallback implements ProviderBWithFallback {
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public String info() {
|
public String info() {
|
||||||
// return "fallback: trigger the refuse for service b";
|
return "fallback: trigger the refuse for service b";
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.tencent.cloud.polaris.circuitbreaker.feign.example;
|
||||||
|
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
@FeignClient(name = "polaris-circuitbreaker-callee-service", contextId = "use-code-fallback", fallback = ProviderBFallback.class)
|
||||||
|
public interface ProviderBWithFallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get info of service B.
|
||||||
|
*
|
||||||
|
* @return info of service B
|
||||||
|
*/
|
||||||
|
@GetMapping("/example/service/b/info")
|
||||||
|
String info();
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue