From ec1f65f99da578f28529116f090f2c9133d8e1f9 Mon Sep 17 00:00:00 2001 From: theonefx Date: Tue, 6 Jul 2021 12:53:03 +0800 Subject: [PATCH] use aop to save and get FeignClientFactoryBean replace to applicationContext.getBean --- .../cloud/sentinel/feign/SentinelFeign.java | 59 ++++++++++--------- .../feign/SentinelFeignAutoConfiguration.java | 7 +++ .../feign/SentinelTargeterAspect.java | 51 ++++++++++++++++ 3 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelTargeterAspect.java 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 5b2f89d85..c0809fa9f 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 @@ -80,34 +80,37 @@ public final class SentinelFeign { // 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); + Object feignClientFactoryBean = SentinelTargeterAspect + .getFeignClientFactoryBean(); + + if (feignClientFactoryBean != null) { + 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); + } } 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/SentinelFeignAutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeignAutoConfiguration.java index 5a7ba59c4..d78dd0b2e 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeignAutoConfiguration.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeignAutoConfiguration.java @@ -41,4 +41,11 @@ public class SentinelFeignAutoConfiguration { return SentinelFeign.builder(); } + @Bean + @ConditionalOnProperty(name = "feign.sentinel.enabled") + @ConditionalOnClass(name = "org.springframework.cloud.openfeign.Targeter") + public SentinelTargeterAspect sentinelTargeterAspect() { + return new SentinelTargeterAspect(); + } + } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelTargeterAspect.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelTargeterAspect.java new file mode 100644 index 000000000..69873b52c --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelTargeterAspect.java @@ -0,0 +1,51 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * 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 CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.sentinel.feign; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Record FeignClientFactoryBean to threadlocal, so that SentinelFeign can get it when + * creating SentinelInvocationHandler. + * + * @see com.alibaba.cloud.sentinel.feign.SentinelFeign.Builder + * @author theonefx + */ +@Aspect +public class SentinelTargeterAspect { + + private static final ThreadLocal FEIGN_CLIENT_FACTORY_BEAN = new ThreadLocal<>(); + + public static Object getFeignClientFactoryBean() { + return FEIGN_CLIENT_FACTORY_BEAN.get(); + } + + @Around("execution(* org.springframework.cloud.openfeign.Targeter.target(..))") + public Object process(ProceedingJoinPoint pjp) throws Throwable { + Object factory = pjp.getArgs()[0]; + try { + FEIGN_CLIENT_FACTORY_BEAN.set(factory); + return pjp.proceed(); + } + finally { + FEIGN_CLIENT_FACTORY_BEAN.remove(); + } + } + +}