diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/pom.xml b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/pom.xml index 3b52c94c3..28604c272 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/pom.xml +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/pom.xml @@ -77,13 +77,13 @@ org.springframework.cloud - spring-cloud-starter-loadbalancer + spring-cloud-commons true org.springframework.cloud - spring-cloud-commons + spring-cloud-starter-loadbalancer true diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeign.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeign.java index bb8044748..953463ad6 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeign.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeign.java @@ -25,16 +25,20 @@ import feign.Contract; import feign.Feign; import feign.InvocationHandlerFactory; import feign.Target; -//import feign.hystrix.FallbackFactory; -//import feign.hystrix.HystrixFeign; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.cloud.openfeign.FallbackFactory; +import org.springframework.cloud.openfeign.FeignClientFactoryBean; import org.springframework.cloud.openfeign.FeignContext; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; +import static org.springframework.beans.factory.BeanFactory.FACTORY_BEAN_PREFIX; + /** * {@link Feign.Builder} like {@link HystrixFeign.Builder}. * @@ -77,38 +81,43 @@ public final class SentinelFeign { @Override public InvocationHandler create(Target target, Map dispatch) { - // using reflect get fallback and fallbackFactory properties from - // FeignClientFactoryBean because FeignClientFactoryBean is a package - // level class, we can not use it in our package -// Object feignClientFactoryBean = Builder.this.applicationContext -// .getBean("&" + target.type().getName()); -// -// Class fallback = (Class) getFieldValue(feignClientFactoryBean, -// "fallback"); -// Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean, -// "fallbackFactory"); -// String beanName = (String) getFieldValue(feignClientFactoryBean, -// "contextId"); -// if (!StringUtils.hasText(beanName)) { -// beanName = (String) getFieldValue(feignClientFactoryBean, "name"); -// } -// -// Object fallbackInstance; -// FallbackFactory fallbackFactoryInstance; -// // check fallback and fallbackFactory properties -// if (void.class != fallback) { -// fallbackInstance = getFromContext(beanName, "fallback", fallback, -// target.type()); -// return new SentinelInvocationHandler(target, dispatch, -// new FallbackFactory.Default(fallbackInstance)); -// } -// if (void.class != fallbackFactory) { -// fallbackFactoryInstance = (FallbackFactory) getFromContext( -// beanName, "fallbackFactory", fallbackFactory, -// FallbackFactory.class); -// return new SentinelInvocationHandler(target, dispatch, -// fallbackFactoryInstance); -// } + + GenericApplicationContext gctx = (GenericApplicationContext) Builder.this.applicationContext; + BeanDefinition def = gctx.getBeanDefinition(target.type().getName()); + + /** + * TODO + * 由于初始化顺序发生变更,这里为了避免循环依赖,只能通过 BeanDefinition 的方式获得 FeignClientFactoryBean + * 需要重点review + */ +// FeignClientFactoryBean feignClientFactoryBean = (FeignClientFactoryBean) Builder.this.applicationContext +// .getBean(FACTORY_BEAN_PREFIX + target.type().getName()); + FeignClientFactoryBean feignClientFactoryBean = (FeignClientFactoryBean) def.getAttribute("feignClientsRegistrarFactoryBean"); + + Class fallback = feignClientFactoryBean.getFallback(); + Class fallbackFactory = feignClientFactoryBean.getFallbackFactory(); + String beanName = feignClientFactoryBean.getContextId(); + + if (!StringUtils.hasText(beanName)) { + beanName = feignClientFactoryBean.getName(); + } + + Object fallbackInstance; + FallbackFactory fallbackFactoryInstance; + // check fallback and fallbackFactory properties + if (void.class != fallback) { + fallbackInstance = getFromContext(beanName, "fallback", fallback, + target.type()); + return new SentinelInvocationHandler(target, dispatch, + new FallbackFactory.Default(fallbackInstance)); + } + if (void.class != fallbackFactory) { + fallbackFactoryInstance = (FallbackFactory) getFromContext( + beanName, "fallbackFactory", fallbackFactory, + FallbackFactory.class); + return new SentinelInvocationHandler(target, dispatch, + fallbackFactoryInstance); + } return new SentinelInvocationHandler(target, dispatch); } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelInvocationHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelInvocationHandler.java index 85144c05f..18ff4e7e7 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelInvocationHandler.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelInvocationHandler.java @@ -23,6 +23,8 @@ import java.lang.reflect.Proxy; import java.util.LinkedHashMap; import java.util.Map; +import org.springframework.cloud.openfeign.FallbackFactory; + import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.SphU; @@ -47,8 +49,18 @@ public class SentinelInvocationHandler implements InvocationHandler { private final Map dispatch; + private FallbackFactory fallbackFactory; + private Map fallbackMethodMap; + SentinelInvocationHandler(Target target, Map dispatch, + FallbackFactory fallbackFactory) { + this.target = checkNotNull(target, "target"); + this.dispatch = checkNotNull(dispatch, "dispatch"); + this.fallbackFactory = fallbackFactory; + this.fallbackMethodMap = toFallbackMethod(dispatch); + } + SentinelInvocationHandler(Target target, Map dispatch) { this.target = checkNotNull(target, "target"); this.dispatch = checkNotNull(dispatch, "dispatch"); @@ -100,8 +112,25 @@ public class SentinelInvocationHandler implements InvocationHandler { if (!BlockException.isBlockException(ex)) { Tracer.trace(ex); } - // throw exception if fallbackFactory is null - throw ex; + if (fallbackFactory != null) { + try { + Object fallbackResult = fallbackMethodMap.get(method) + .invoke(fallbackFactory.create(ex), args); + return fallbackResult; + } + catch (IllegalAccessException e) { + // shouldn't happen as method is public due to being an + // interface + throw new AssertionError(e); + } + catch (InvocationTargetException e) { + throw new AssertionError(e.getCause()); + } + } + else { + // throw exception if fallbackFactory is null + throw ex; + } } finally { if (entry != null) {