最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

FeignClientFactoryBean創(chuàng)建動態(tài)代理詳細(xì)解讀

 更新時間:2023年11月21日 09:12:20   作者:dalianpai  
這篇文章主要介紹了FeignClientFactoryBean創(chuàng)建動態(tài)代理詳細(xì)解讀,當(dāng)直接進(jìn)去注冊的方法中,一步步放下走,都是直接放bean的定義信息中放入值,然后轉(zhuǎn)成BeanDefinitionHolder,最后在注冊到IOC容器中,需要的朋友可以參考下

FeignClientFactoryBean創(chuàng)建動態(tài)代理

探索FeignClient的注冊流程

當(dāng)直接進(jìn)去注冊的方法中,一步步放下走,都是直接放bean的定義信息中放入值,然后轉(zhuǎn)成BeanDefinitionHolder,最后在注冊到IOC容器中。 具體的信息可以看下面斷點的圖。

image-20211019140122997

image-20211019140213072

在仔細(xì)看一下就會發(fā)現(xiàn)很奇怪,為什么此處傳入的是FeignClientFactoryBean,然后把feignclient的信息放它的里面,那我們就進(jìn)去看看。

那我們就進(jìn)行看一下FeignClientFactoryBean,里面的內(nèi)容

image-20211019140829389

首先發(fā)現(xiàn)它實現(xiàn)了FactoryBean接口,可以返回bean的實例的工廠bean,通過實現(xiàn)該接口可以對bean進(jìn)行一些額外的操作。此處肯定重寫了getObject方法,就是在此處,這個方法可以往容器中注入Bean的。

@Override
	public Object getObject() throws Exception {
		return getTarget();
	}
 
<T> T getTarget() {
		FeignContext context = this.applicationContext.getBean(FeignContext.class);
		Feign.Builder builder = feign(context);
 
		if (!StringUtils.hasText(this.url)) {
			if (!this.name.startsWith("http")) {
				this.url = "http://" + this.name;
			}
			else {
				this.url = this.name;
			}
			this.url += cleanPath();
			return (T) loadBalance(builder, context,
					new HardCodedTarget<>(this.type, this.name, this.url));
		}
		if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
			this.url = "http://" + this.url;
		}
		String url = this.url + cleanPath();
		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();
			}
			if (client instanceof FeignBlockingLoadBalancerClient) {
				// not load balancing because we have a url,
				// but Spring Cloud LoadBalancer is on the classpath, so unwrap
				client = ((FeignBlockingLoadBalancerClient) 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));
	}

在getObject?法中,?先從applicationContext中、也就是從Spring容器中獲取了?個FeignContext組件,應(yīng)該是Feign存放?具類的?個上下?組件,然后從FeignContext中獲取到了FeignLoggerFactory組件,?路追進(jìn)去發(fā)現(xiàn),原來在底層也是維護(hù)了?個Spring容器的緩存Map<String, AnnotationConfigApplicationContext>。Feign在執(zhí)?時涉及到?系列的組件,所以Feign?脆為每個服務(wù)創(chuàng)建了?個Spring容器類ApplicationContext,?來存放每個服務(wù)各?所需要的組件,每個服務(wù)的這些?具類、組件都是互不影 響的,所以我們看到它在底層是通過?個Map來緩存的,key為服務(wù)名,value為服務(wù)所對應(yīng)的的spring 容器ApplicationContext。

接下來我們陸續(xù)看到了其他的組件如:Decoder、Encoder、Contract等都被創(chuàng)建了出來,都設(shè)置到了Feign.Builder組件中,看來Feign.Builder應(yīng)該是要為創(chuàng)建對象設(shè)置?些必要的組件信息。

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;
	}

但是發(fā)現(xiàn)FeignContext、FeignLoggerFactory還是Encoder、Decoder、Contract,他們都是接?

image-20211019150645159

發(fā)現(xiàn)在同包下面還有一個FeignClientsConfiguration配置類,那就點進(jìn)去看看。

image-20211019150847945

image-20211019151005982

Decoder、Encoder、Contract、FeignLoggerFactory的實際類型都很順利的找到了。 因為Feign最終還是要發(fā)送HTTP請求,這?就難免要涉及到序列化和反序列化、這個過程就會牽扯到編碼和解碼的過程,Encoder和Decoder就派上?場了。 因為Feign?帶的注解@FeignClient、以及SpringMVC注解它們是被誰處理的呢?Contract的實現(xiàn)類SpringMVCContract就是來解析它們的,解析所有的注解信息、然后拼湊成?個完整的HTTP請求所需要的信息。

image-20211019144245884

在最后一行,有一個這個方法configureFeign(context, builder);,看方法名字就是配置feign,猜一猜應(yīng)該是把配置文件的一些配置綁定到feign的配置類上。

protected void configureFeign(FeignContext context, Feign.Builder builder) {
		FeignClientProperties properties = this.applicationContext
				.getBean(FeignClientProperties.class);
 
		FeignClientConfigurer feignClientConfigurer = getOptional(context,
				FeignClientConfigurer.class);
		setInheritParentContext(feignClientConfigurer.inheritParentConfiguration());
 
		if (properties != null && inheritParentContext) {
			if (properties.isDefaultToProperties()) {
                               //這行默認(rèn)取的是配置文件的信息。
				configureUsingConfiguration(context, builder);
                              //這行取的是yml中的默認(rèn)配置
				configureUsingProperties(
						properties.getConfig().get(properties.getDefaultConfig()),
						builder);
                              //這行是yml中指定服務(wù)的配置
				configureUsingProperties(properties.getConfig().get(this.contextId),
						builder);
			}
			else {
				configureUsingProperties(
						properties.getConfig().get(properties.getDefaultConfig()),
						builder);
				configureUsingProperties(properties.getConfig().get(this.contextId),
						builder);
				configureUsingConfiguration(context, builder);
			}
		}
		else {
			configureUsingConfiguration(context, builder);
		}
	}

下圖為配置類中的信息

image-20211020101245947

下面為指定服務(wù)的yml中的信息

image-20211020101338558

image-20211020101454713

服務(wù)的配置信息優(yōu)先級是要?默認(rèn)配置要?的,所以也會覆蓋默認(rèn)的配置信息。

分析到這?,F(xiàn)eign要創(chuàng)建?個對象的所需要的信息都設(shè)置的差不多了,簡單來說就四?部分:

(1)默認(rèn)的組件

(2)?定義組件

(3)默認(rèn)的配置信息

(4)指定服務(wù)的配置信息

創(chuàng)建Feign的動態(tài)代理對象

然后我們就繼續(xù)放行,最終得到了Feign.Builder對象,然后我們繼續(xù)放行,來到了截圖的哪行,這里會返回一個對象。

image-20211019144325708

點進(jìn)去,我們繼續(xù)分析,第一行我們直接過,但是看idea的提示類型是LoadBalancerFeignClient,LoadBalancer是ribbon的三大核心組件之一,應(yīng)該是和reibbon負(fù)載均衡有關(guān)系。

image-20211019144547474

那我們就找一下它是在那個配置類被創(chuàng)建的。

image-20211020104444844

接下來,我們看到它直接從容器中獲取了?個Targeter對象,這個對象是HystrixTargeter對象,在FeignAutoConfiguration 中找到、然后直接調(diào)?target?法,如下圖所示:

image-20211020102344252

那我們就來到它的這個方法中,繼續(xù)放下放行:

image-20211020104727702

?路順勢跟到??后發(fā)現(xiàn),target?法中、調(diào)?了build?法,??創(chuàng)建了SynchronousMethodHandler.Factory,翻譯起來也就是同步?法處理器的??類,具體?什么?的、?前也不是好確定,反正只知道??就是?來創(chuàng)建對象?的,然后它把這個??類放到了ParseHandlersByName中,并且new上了?個ReflectiveFeign對象并返回了。

緊接著調(diào)?了newInstance?法,看樣?是要創(chuàng)建?個對象,繼續(xù)跟進(jìn)看下:

public <T> T target(Target<T> target) {
      return build().newInstance(target);
    }
 
@Override
  public <T> T newInstance(Target<T> target) {
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
 
    for (Method method : target.type().getMethods()) {
      if (method.getDeclaringClass() == Object.class) {
        continue;
      } else if (Util.isDefault(method)) {
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    InvocationHandler handler = factory.create(target, methodToHandler);
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);
 
    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }

看見 InvocationHandler handler = factory.create(target, methodToHandler);這行,基本就可以確定,是創(chuàng)建了動態(tài)代理。因為前面解析@FeignClient注解,并且封裝了一個Bean的定義信息注冊中Ioc容器中,比較ServiceAClient畢竟是一個接口,所以給每個接口創(chuàng)建了一個動態(tài)代理,然后調(diào)用接口時,去讓動態(tài)代理來執(zhí)行

image-20211019155531287

一進(jìn)入到這個方法中,會看到有2個Map和一個List,那我們就先看一下第一個map,里面的數(shù)據(jù)如下圖:

image-20211019160113229

當(dāng)我們點進(jìn)apply方法的時候,進(jìn)?到apply?法中、發(fā)現(xiàn)contract通過調(diào)?parseAndValidateMetadata?法得到了、List 、也就是接?中的所有?法的元數(shù)據(jù)信息,然后遍歷這些?法,通過factory創(chuàng)建MethodHandler,?這?的 factory就是我們前?在build?法中看到的SynchronousMethodHandler.Factory 。

image-20211019161015024

后面的話,會遍歷所有的nameToHandler,把它轉(zhuǎn)成methodToHandler。image-20211020110050039

最終來到了這行InvocationHandler handler = factory.create(target, methodToHandler);把上面獲取到的方法和要代理的對象都放到了FeignInvocationHandler中。

最終創(chuàng)建出了代理對象。

到此這篇關(guān)于FeignClientFactoryBean創(chuàng)建動態(tài)代理詳細(xì)解讀的文章就介紹到這了,更多相關(guān)FeignClientFactoryBean動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java程序員必會的遠(yuǎn)程debug教程

    java程序員必會的遠(yuǎn)程debug教程

    這篇文章主要為大家介紹了java程序員必會的遠(yuǎn)程debug教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • spring與mybatis整合配置文件

    spring與mybatis整合配置文件

    本文通過實例代碼給大家介紹了spring與mybatis整合配置文件的方法,需要的朋友參考下吧
    2017-09-09
  • Java中的字符編碼問題處理心得總結(jié)

    Java中的字符編碼問題處理心得總結(jié)

    Java中的String類默認(rèn)是Unicode編碼,大家平常所說的UTF-8就是使用最廣的一種unicode的實現(xiàn)方式,以下我們還是來看一下Java中的字符編碼問題處理心得總結(jié):
    2016-06-06
  • Aop動態(tài)代理和cglib實現(xiàn)代碼詳解

    Aop動態(tài)代理和cglib實現(xiàn)代碼詳解

    這篇文章主要介紹了Aop動態(tài)代理和cglib實現(xiàn)代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-12-12
  • SpringBoot實現(xiàn)優(yōu)雅停機(jī)的流程步驟

    SpringBoot實現(xiàn)優(yōu)雅停機(jī)的流程步驟

    優(yōu)雅停機(jī)(Graceful Shutdown) 是指在服務(wù)器需要關(guān)閉或重啟時,能夠先處理完當(dāng)前正在進(jìn)行的請求,然后再停止服務(wù)的操作,本文給大家介紹了SpringBoot實現(xiàn)優(yōu)雅停機(jī)的流程步驟,需要的朋友可以參考下
    2024-03-03
  • spring cloud gateway網(wǎng)關(guān)路由分配代碼實例解析

    spring cloud gateway網(wǎng)關(guān)路由分配代碼實例解析

    這篇文章主要介紹了spring cloud gateway網(wǎng)關(guān)路由分配代碼實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • idea+spring?boot創(chuàng)建項目的搭建全過程

    idea+spring?boot創(chuàng)建項目的搭建全過程

    Spring?Boot是Spring社區(qū)發(fā)布的一個開源項目,旨在幫助開發(fā)者快速并且更簡單的構(gòu)建項目,這篇文章主要介紹了idea+spring?boot創(chuàng)建項目的搭建全過程,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-09-09
  • Java讀取XML實現(xiàn)過程(DOM方式)

    Java讀取XML實現(xiàn)過程(DOM方式)

    文章介紹了如何使用Java的DOM方式讀取XML文件,并詳細(xì)說明了讀取過程中需要注意的事項,如文件路徑、節(jié)點層級和屬性值的獲取方式,作者通過一個示例代碼展示了如何實現(xiàn)XML的讀取,并總結(jié)了自己的經(jīng)驗,希望對讀者有所幫助
    2025-11-11
  • 解決BeanUtils.copyProperties無法成功封裝的問題

    解決BeanUtils.copyProperties無法成功封裝的問題

    這篇文章主要介紹了解決BeanUtils.copyProperties無法成功封裝的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • springboot環(huán)境下配置使用sqlite數(shù)據(jù)庫方式

    springboot環(huán)境下配置使用sqlite數(shù)據(jù)庫方式

    這篇文章主要介紹了springboot環(huán)境下配置使用sqlite數(shù)據(jù)庫方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評論

武陟县| 石渠县| 当涂县| 宾阳县| 巩义市| 井冈山市| 蓬溪县| 黎平县| 元朗区| 汉阴县| 琼中| 西贡区| 达州市| 全州县| 法库县| 阿鲁科尔沁旗| 睢宁县| 右玉县| 徐汇区| 连山| 沅陵县| 义乌市| 介休市| 云浮市| 体育| 漾濞| 博罗县| 德清县| 大荔县| 岑溪市| 伊宁县| 乐山市| 台东市| 建平县| 永州市| 沙雅县| 平南县| 西乡县| 汽车| 伊金霍洛旗| 浪卡子县|