摘要:重要以及內(nèi)部類都是訪問(wèn)級(jí)別,可以注入自定義的。的目的是將包裝成風(fēng)格以便開(kāi)發(fā)。示例以下示例參考其中的和是自定義的。需要自定義,則實(shí)現(xiàn)類,需要自定義,則實(shí)現(xiàn)即可總結(jié)由于構(gòu)建過(guò)程所用到的是訪問(wèn)級(jí)別的,不能使用自定義的以及是,給了我們擴(kuò)展的空間。
spring-cloud-openfeign-core-2.1.1.RELEASE.jar 中 HystrixFeign 的詳細(xì)構(gòu)建過(guò)程:
@EnableFeignClients -> FeignClientsRegistrar 掃描 @Feign注解的類 -> FeignClientFactoryBean通過(guò)Targeter生產(chǎn)FeignClient -> Targeter通過(guò)Feign.Builder構(gòu)建Feign -> Feign.Builder
1. 準(zhǔn)備工作(配置)FeignAutoConfiguration自動(dòng)配置類
@Configuration @ConditionalOnClass(name = "feign.hystrix.HystrixFeign") protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); } } @Configuration @ConditionalOnMissingClass("feign.hystrix.HystrixFeign") protected static class DefaultFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new DefaultTargeter(); } }
feign.hystrix.HystrixFeign類存在時(shí),將 HystrixTargeter 注冊(cè)為 Targeter 類型的 bean
feign.hystrix.HystrixFeign類不存在時(shí),使用 DefaultTargeter 。
看起來(lái)似乎可以使用自定義的Targeter代替Hystrix或默認(rèn)的,這樣就可以自定義各種功能了。實(shí)際上不行,因?yàn)?Targeter 是 package 訪問(wèn)級(jí)別的。
FeignClientsConfiguration
@Configuration public class FeignClientsConfiguration { @Bean @ConditionalOnMissingBean public Retryer feignRetryer() { return Retryer.NEVER_RETRY; } @Bean @Scope("prototype") @ConditionalOnMissingBean public Feign.Builder feignBuilder(Retryer retryer) { return Feign.builder().retryer(retryer); } @Configuration @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class }) protected static class HystrixFeignConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean @ConditionalOnProperty(name = "feign.hystrix.enabled") public Feign.Builder feignHystrixBuilder() { return HystrixFeign.builder(); } } }
重要:Feign 以及內(nèi)部類 Feign.Builder 都是 public 訪問(wèn)級(jí)別,可以注入自定義的bean。
2.EnableFeignClients與FeignClientsRegistrar類將使用@FeignClient注解的類注冊(cè)成spring bean,并使用注解中的配置
在@EnableFeignClients注解中導(dǎo)入FeignClientsRegistrar類
FeignClientsRegistrar類實(shí)現(xiàn)了ImportBeanDefinitionRegistrar類,會(huì)由spring框架執(zhí)行實(shí)現(xiàn)方法 registerBeanDefinitions(AnnotationMetaData, BeanDefinitionRegistry)
FeignClientsRegistrar中的 registerBeanDefinitions方法調(diào)用兩個(gè)方法
registerDefaultConfiguration:注冊(cè)默認(rèn)的配置
registerFeignClients:注冊(cè)Feign客戶端(重點(diǎn))
registerFeignClients:獲取 @EnableFeignClients注解中定義的配置掃描feign客戶端
registerFeignClients:通過(guò)registerFeignClient(BeanDefinitionRegistry, AnnotationMetadata, Map)方法注冊(cè)每一個(gè)feignClient,過(guò)程:先獲取 @FeignClient注解中定義的配置,將配置應(yīng)用在spring bean 工廠 FeignClientFactoryBean, 通過(guò)工廠類 FeignClientFactoryBean 為每一個(gè)使用@FeignClient注解的類生產(chǎn) FeignClient,詳細(xì)過(guò)程見(jiàn)下一節(jié)
3.FeignClientFactoryBeanFeignClient工廠bean。
class FeignClientFactoryBean implements FactoryBean
通過(guò)實(shí)現(xiàn)方法 FactoryBean#getObject()來(lái)由spring框架生產(chǎn)FeignClient。
@Override public Object getObject() throws Exception { return getTarget(); } /** * 獲得目標(biāo) * 1. 獲得FeignContext * 2. 從FeignContext中獲得Feign構(gòu)建器Feign.Builder * 3. 從FeignContext中獲得Client,判斷是否進(jìn)行負(fù)載均衡 * 4. 從FeignContext中獲得Target,并執(zhí)行Target的默認(rèn)方法target(FeignClientFactoryBean, Feign.Builder, FeignContext, Target.HardCodedTarget); * 5.由于一開(kāi)始注入的Feign.Builder是HystrixFeign.Builder,則此處是調(diào)用HystrixFeign.Builder里的對(duì)應(yīng)方法 */ T getTarget() { FeignContext context = this.applicationContext.getBean(FeignContext.class); Feign.Builder builder = feign(context); //省略部分代碼 // ...... Client client = getOptional(context, Client.class); if (client != null) { if (client instanceof LoadBalancerFeignClient) { // not load balancing because we have a url, // but ribbon is on the classpath, so unwrap client = ((LoadBalancerFeignClient) client).getDelegate(); } builder.client(client); } Targeter targeter = get(context, Targeter.class); return (T) targeter.target(this, builder, context, new HardCodedTarget<>(this.type, this.name, url)); } protected Feign.Builder feign(FeignContext context) { FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class); Logger logger = loggerFactory.create(this.type); // @formatter:off Feign.Builder builder = get(context, Feign.Builder.class) // required values .logger(logger) .encoder(get(context, Encoder.class)) .decoder(get(context, Decoder.class)) .contract(get(context, Contract.class)); // @formatter:on configureFeign(context, builder); return builder; }
工廠獲得對(duì)象(目標(biāo)):
1. 獲得FeignContext(feign上下文) 2. 從FeignContext中獲得Feign構(gòu)建器Feign.Builder(public,可以在此使用自定義構(gòu)建器) 3. 從FeignContext中獲得Client,判斷是否進(jìn)行負(fù)載均衡 4. 從FeignContext中獲得Target,并執(zhí)行Target的默認(rèn)方法target(FeignClientFactoryBean, Feign.Builder, FeignContext, Target.HardCodedTarget4.Targeter 4.1.HystrixTargeter); 5. 由于一開(kāi)始注入的 *Targeter* 是 *HystrixTargeter* ,則此處是調(diào)用 HystrixTargeter 里的對(duì)應(yīng)方法(從第一節(jié)的配置來(lái)看,只要 *feign.hystrix.HystrixFeign* 類存在,就是注入的 *HystrixTargeter *, 否則是 *DefaultTargeter*,對(duì)于需要**自定義構(gòu)建feign的,這里不太重要**)
class HystrixTargeter implements Targeter { @Override publicT target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { // 若不是 HystrixFeign,則執(zhí)行其對(duì)應(yīng)的默認(rèn)target方法。 // 此處只處理HystrixFeign。 if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { return feign.target(target); } feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; SetterFactory setterFactory = getOptional(factory.getName(), context, SetterFactory.class); if (setterFactory != null) { builder.setterFactory(setterFactory); } Class> fallback = factory.getFallback(); if (fallback != void.class) { return targetWithFallback(factory.getName(), context, target, builder, fallback); } Class> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) { return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory); } // 調(diào)用從Feign.Builder繼承的方法。 return feign.target(target); } private T targetWithFallbackFactory(String feignClientName, FeignContext context, Target.HardCodedTarget target, HystrixFeign.Builder builder, Class> fallbackFactoryClass) { FallbackFactory extends T> fallbackFactory = (FallbackFactory extends T>) getFromContext( "fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class); return builder.target(target, fallbackFactory); } private T targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget target, HystrixFeign.Builder builder, Class> fallback) { T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type()); return builder.target(target, fallbackInstance); } //... }
HystrixTarget只處理 Feign.Builder 類型為 feign.hystrix.HystrixFeign.Builder 的
若feign構(gòu)建器不是 feign.hystrix.HystrixFeign.Builder 類型,則執(zhí)行注入的 feign 構(gòu)建器的默認(rèn)target方法
因此,即使注入的 Targeter 是 HystrixTargeter,此處也可以執(zhí)行自定義 Feign.Builder。
理解:Feign.Builder#target(Target) 方法通常不會(huì)被 override(后續(xù)會(huì)講解為什么不重寫(xiě)此方法)
4.2.DefaultTargeterclass DefaultTargeter implements Targeter { @Override publicT target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { return feign.target(target); } }
執(zhí)行 Feign.Builder (子)類型對(duì)應(yīng)的 默認(rèn) target方法。
理解:Feign.Builder#target(Target) 方法通常不會(huì)被 override(后續(xù)會(huì)講解為什么不重寫(xiě)此方法)
5.FeignBuilderfeign構(gòu)建器:構(gòu)建feign對(duì)象。
Feign的目的是將 http api 包裝成 restful 風(fēng)格以便開(kāi)發(fā)。在實(shí)現(xiàn)中,F(xiàn)eign 是一個(gè)為目標(biāo)http apis 生成 feign對(duì)象(Feign#newInstance)的工廠。
上述步驟目前需要的都是通過(guò)對(duì)應(yīng)的 Builder 構(gòu)建對(duì)應(yīng)的Feign。
public abstract class Feign { public static Builder builder() { return new Builder(); } public abstractT newInstance(Target target); public static class Builder { public T target(Target target) { return build().newInstance(target); } public Feign build() { SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy); ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, errorDecoder, synchronousMethodHandlerFactory); return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); } } }
Feign.Builder#target(Target) 方法里面實(shí)際上調(diào)用的是 build() 方法來(lái)構(gòu)建對(duì)象,因此重寫(xiě) build() 方法即可,沒(méi)有必要還重寫(xiě) target(Target) 方法
Feign 以及內(nèi)部類 Feign.Builder 都是 public ,可以重寫(xiě)并注入自定義的bean。
5.1.HystrixFeignpublic final class HystrixFeign { public static final class Builder extends Feign.Builder { @Override public Feign build() { return build(null); } // 提供一系列的target方法,支持各種配置:fallback、FallBackFactory等 publicT target(Target target, T fallback) { return build(fallback != null ? new FallbackFactory.Default (fallback) : null) .newInstance(target); } public T target(Target target, FallbackFactory extends T> fallbackFactory) { return build(fallbackFactory).newInstance(target); } public T target(Class apiType, String url, T fallback) { return target(new Target.HardCodedTarget (apiType, url), fallback); } public T target(Class apiType, String url, FallbackFactory extends T> fallbackFactory) { return target(new Target.HardCodedTarget (apiType, url), fallbackFactory); } /** Configures components needed for hystrix integration. */ Feign build(final FallbackFactory> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map dispatch) { return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); }
基本到了這一步,需要設(shè)置的東西,都可以配置了。
雖然 build 方法中涉及到 InvocationHandler,但基本不需要改什么,而 InvocationHandler 竟然也是 package 訪問(wèn)級(jí)別,所以只好復(fù)制一個(gè),使用自己的。
HystrixDelegatingContract 是 public 級(jí)別,不需要修改的話,仍然用這個(gè)。
5.2示例以下示例參考 SentinelFeign
其中的 YiFeiXiInvocationHandler 和 YiFeiXiFeignFallbackFactory是自定義的。
@Override public Feign build() { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Mapdispatch) { // 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 name = (String) getFieldValue(feignClientFactoryBean, "name"); Object fallbackInstance; FallbackFactory fallbackFactoryInstance; // check fallback and fallbackFactory properties // 以下邏輯在HystrixTargeter中有,但執(zhí)行自定義的builder,不會(huì)執(zhí)行到那段邏輯,因此此處加上。 if (void.class != fallback) { fallbackInstance = getFromContext(name, "fallback", fallback, target.type()); return new YiFeiXiInvocationHandler(target, dispatch, setterFactory, new FallbackFactory.Default(fallbackInstance)); } if (void.class != fallbackFactory) { fallbackFactoryInstance = (FallbackFactory) getFromContext(name, "fallbackFactory", fallbackFactory, FallbackFactory.class); return new YiFeiXiInvocationHandler(target, dispatch, setterFactory, fallbackFactoryInstance); } // 若注解中沒(méi)有使用fallback或fallbackFactory,則使用一個(gè)默認(rèn)的FallbackFactory。 return new YiFeiXiInvocationHandler(target, dispatch, setterFactory, new YiFeiXiFeignFallbackFactory<>(target)); } private Object getFromContext(String name, String type, Class fallbackType, Class targetType) { Object fallbackInstance = feignContext.getInstance(name, fallbackType); if (fallbackInstance == null) { throw new IllegalStateException(String.format( "No %s instance of type %s found for feign client %s", type, fallbackType, name)); } if (!targetType.isAssignableFrom(fallbackType)) { throw new IllegalStateException(String.format( "Incompatible %s instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s", type, fallbackType, targetType, name)); } return fallbackInstance; } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); }
需要自定義fallbackFactory,則實(shí)現(xiàn) feign.hystrix.FallbackFactory類,需要自定義fallback,則實(shí)現(xiàn) org.springframework.cglib.proxy.MethodInterceptor即可
6.總結(jié)由于Feign構(gòu)建過(guò)程所用到的 Targeter 是 package 訪問(wèn)級(jí)別的,不能使用自定義的
Feign以及Feign.Builder是 publilc,給了我們擴(kuò)展的空間。
7.參考資料feign-hystrix-10.1.0.jar和spring-cloud-openfeign-core-2.1.1.RELEASE.jar
spring-cloud-alibaba-sentinel-0.9.0.RELEASE.jar中的 sentinelFeign 實(shí)現(xiàn)
Spring Cloud Alibaba Sentinel 整合 Feign 的設(shè)計(jì)實(shí)現(xiàn)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74639.html
摘要:作用跟一致跟屬性作用一致給設(shè)置注解絕對(duì)路徑,用于替換服務(wù)名。在服務(wù)名或與之間默認(rèn)是,表示當(dāng)前這個(gè)生成的是否是。內(nèi)部的能獲取服務(wù)名信息,的實(shí)現(xiàn)類能拿到對(duì)應(yīng)的請(qǐng)求路徑信息。很不幸,這個(gè)類也是包級(jí)別的類。整合的代碼目前已經(jīng)在倉(cāng)庫(kù)上,但是沒(méi)未發(fā)版。 作者 | Spring Cloud Alibaba 高級(jí)開(kāi)發(fā)工程師洛夜來(lái)自公眾號(hào)阿里巴巴中間件投稿 前段時(shí)間 Hystrix 宣布不再維護(hù)之后(H...
摘要:內(nèi)部使用了的動(dòng)態(tài)代理為目標(biāo)接口生成了一個(gè)動(dòng)態(tài)代理類,這里會(huì)生成一個(gè)動(dòng)態(tài)代理原理統(tǒng)一的方法攔截器,同時(shí)為接口的每個(gè)方法生成一個(gè)攔截器,并解析方法上的元數(shù)據(jù),生成一個(gè)請(qǐng)求模板。的核心源碼解析到此結(jié)束了,不知道是否對(duì)您有無(wú)幫助,可留言跟我交流。 Feign是一個(gè)聲明式的Web服務(wù)客戶端。這使得Web服務(wù)客戶端的寫(xiě)入更加方便 要使用Feign創(chuàng)建一個(gè)界面并對(duì)其進(jìn)行注釋。它具有可插拔注釋支持,包...
摘要:接下來(lái)通過(guò)詳細(xì)的步驟介紹如何接入微信二次分享操作。不要嘗試在中使用異步請(qǐng)求修改本次分享的內(nèi)容,因?yàn)榭蛻舳朔窒聿僮魇且粋€(gè)同步操作,這時(shí)候使用的回包會(huì)還沒(méi)有返回用戶點(diǎn)擊分享到朋友圈已分享已取消此時(shí)微信二次分享就已經(jīng)大功告成了。 微信二次分享 效果演示 showImg(https://segmentfault.com/img/remote/1460000016895951); 如何運(yùn)行項(xiàng)目 ...
摘要:接下來(lái)通過(guò)詳細(xì)的步驟介紹如何接入微信二次分享操作。不要嘗試在中使用異步請(qǐng)求修改本次分享的內(nèi)容,因?yàn)榭蛻舳朔窒聿僮魇且粋€(gè)同步操作,這時(shí)候使用的回包會(huì)還沒(méi)有返回用戶點(diǎn)擊分享到朋友圈已分享已取消此時(shí)微信二次分享就已經(jīng)大功告成了。 微信二次分享 效果演示 showImg(https://segmentfault.com/img/remote/1460000016895951); 如何運(yùn)行項(xiàng)目 ...
摘要:接下來(lái)通過(guò)詳細(xì)的步驟介紹如何接入微信二次分享操作。不要嘗試在中使用異步請(qǐng)求修改本次分享的內(nèi)容,因?yàn)榭蛻舳朔窒聿僮魇且粋€(gè)同步操作,這時(shí)候使用的回包會(huì)還沒(méi)有返回用戶點(diǎn)擊分享到朋友圈已分享已取消此時(shí)微信二次分享就已經(jīng)大功告成了。 微信二次分享 效果演示 showImg(https://segmentfault.com/img/remote/1460000016895951); 如何運(yùn)行項(xiàng)目 ...
閱讀 3100·2021-10-12 10:20
閱讀 2826·2021-09-27 13:56
閱讀 802·2021-09-27 13:36
閱讀 1441·2021-09-26 09:46
閱讀 2428·2019-08-30 14:02
閱讀 2696·2019-08-28 18:14
閱讀 1274·2019-08-26 10:32
閱讀 1716·2019-08-23 18:25