亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

探索FeignClient的注冊(cè)流程

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

image-20211019140122997

image-20211019140213072

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

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

image-20211019140829389

首先發(fā)現(xiàn)它實(shí)現(xiàn)了FactoryBean接口,可以返回bean的實(shí)例的工廠bean,通過(guò)實(shí)現(xiàn)該接口可以對(duì)bean進(jìn)行一些額外的操作。此處肯定重寫了getObject方法,就是在此處,這個(gè)方法可以往容器中注入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容器中獲取了?個(gè)FeignContext組件,應(yīng)該是Feign存放?具類的?個(gè)上下?組件,然后從FeignContext中獲取到了FeignLoggerFactory組件,?路追進(jìn)去發(fā)現(xiàn),原來(lái)在底層也是維護(hù)了?個(gè)Spring容器的緩存Map<String, AnnotationConfigApplicationContext>。Feign在執(zhí)?時(shí)涉及到?系列的組件,所以Feign?脆為每個(gè)服務(wù)創(chuàng)建了?個(gè)Spring容器類ApplicationContext,?來(lái)存放每個(gè)服務(wù)各?所需要的組件,每個(gè)服務(wù)的這些?具類、組件都是互不影 響的,所以我們看到它在底層是通過(guò)?個(gè)Map來(lái)緩存的,key為服務(wù)名,value為服務(wù)所對(duì)應(yīng)的的spring 容器ApplicationContext。

接下來(lái)我們陸續(xù)看到了其他的組件如:Decoder、Encoder、Contract等都被創(chuàng)建了出來(lái),都設(shè)置到了Feign.Builder組件中,看來(lái)Feign.Builder應(yīng)該是要為創(chuàng)建對(duì)象設(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)在同包下面還有一個(gè)FeignClientsConfiguration配置類,那就點(diǎn)進(jìn)去看看。

image-20211019150847945

image-20211019151005982

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

image-20211019144245884

在最后一行,有一個(gè)這個(gè)方法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)先級(jí)是要?默認(rèn)配置要?的,所以也會(huì)覆蓋默認(rèn)的配置信息。

分析到這?,F(xiàn)eign要?jiǎng)?chuàng)建?個(gè)對(duì)象的所需要的信息都設(shè)置的差不多了,簡(jiǎn)單來(lái)說(shuō)就四?部分:

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

(2)?定義組件

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

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

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

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

image-20211019144325708

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

image-20211019144547474

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

image-20211020104444844

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

image-20211020102344252

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

image-20211020104727702

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

緊接著調(diào)?了newInstance?法,看樣?是要?jiǎng)?chuàng)建?個(gè)對(duì)象,繼續(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)建了動(dòng)態(tài)代理。因?yàn)榍懊娼馕鯜FeignClient注解,并且封裝了一個(gè)Bean的定義信息注冊(cè)中Ioc容器中,比較ServiceAClient畢竟是一個(gè)接口,所以給每個(gè)接口創(chuàng)建了一個(gè)動(dòng)態(tài)代理,然后調(diào)用接口時(shí),去讓動(dòng)態(tài)代理來(lái)執(zhí)行

image-20211019155531287

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

image-20211019160113229

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

image-20211019161015024

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

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

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

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

相關(guān)文章

  • Java中List排序的3種常見方法總結(jié)

    Java中List排序的3種常見方法總結(jié)

    在Java編程中List對(duì)象的排序是一個(gè)常見的需求,List接口提供了多種排序方法,這篇文章主要給大家介紹了關(guān)于Java中List排序的3種常見方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • Spring中property-placeholder的使用與解析詳解

    Spring中property-placeholder的使用與解析詳解

    本篇文章主要介紹了Spring中property-placeholder的使用與解析詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • springboot開啟mybatis駝峰命名自動(dòng)映射的三種方式

    springboot開啟mybatis駝峰命名自動(dòng)映射的三種方式

    這篇文章給大家總結(jié)springboot開啟mybatis駝峰命名自動(dòng)映射的三種方式,文章并通過(guò)代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2024-02-02
  • SpringBoot項(xiàng)目中使用AOP的方法

    SpringBoot項(xiàng)目中使用AOP的方法

    本篇文章主要介紹了SpringBoot項(xiàng)目中使用AOP的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • Java DOM4J方式生成XML的方法

    Java DOM4J方式生成XML的方法

    今天小編就為大家分享一篇Java DOM4J方式生成XML的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Java數(shù)據(jù)結(jié)構(gòu)之有向圖設(shè)計(jì)與實(shí)現(xiàn)詳解

    Java數(shù)據(jù)結(jié)構(gòu)之有向圖設(shè)計(jì)與實(shí)現(xiàn)詳解

    有向圖是具有方向性的圖,由一組頂點(diǎn)和一組有方向的邊組成,每條方向的邊都連著一對(duì)有序的頂點(diǎn)。本文為大家介紹的是有向圖的設(shè)計(jì)與實(shí)現(xiàn),需要的可以參考一下
    2022-11-11
  • Spring Boot整合swagger使用教程詳解

    Spring Boot整合swagger使用教程詳解

    這篇文章主要介紹了Spring Boot整合swagger使用教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • java 格式化時(shí)間的示例代碼

    java 格式化時(shí)間的示例代碼

    這篇文章主要介紹了java 格式化時(shí)間的示例代碼,幫助大家更好的利用Java處理時(shí)間,感興趣的朋友可以了解下
    2020-12-12
  • drools的簡(jiǎn)單入門案例場(chǎng)景分析

    drools的簡(jiǎn)單入門案例場(chǎng)景分析

    drools是一款由JBoss組織提供的基于Java語(yǔ)言開發(fā)的開源規(guī)則引擎,可以將復(fù)雜且多變的業(yè)務(wù)規(guī)則從硬編碼中解放出來(lái),這篇文章主要介紹了drools的簡(jiǎn)單入門案例,需要的朋友可以參考下
    2022-05-05
  • spring-cloud-gateway動(dòng)態(tài)路由的實(shí)現(xiàn)方法

    spring-cloud-gateway動(dòng)態(tài)路由的實(shí)現(xiàn)方法

    這篇文章主要介紹了spring-cloud-gateway動(dòng)態(tài)路由的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01

最新評(píng)論