【一起學原始碼-微服務】Nexflix Eureka 原始碼二:EurekaServer啟動之配置檔案載入以及面向介面的配置項讀取
前言
上篇文章已經介紹了 為何要讀netflix eureka原始碼了,這裡就不再概述,下面開始正式原始碼解讀的內容。
如若轉載 請標明來源:一枝花算不算浪漫
程式碼總覽
還記得上文中,我們通過web.xml找到了eureka server入口的類EurekaBootStrap
,這裡我們就先來簡單地看下:
/** * The class that kick starts the eureka server. 負責啟動Eureka server的類 * * <p> * 這裡要注意兩個關鍵點: * eureka server對應的配置類為:EurekaServerConfig * eureka client對應的配置類為:EurekaInstanceConfig * * The eureka server is configured by using the configuration * {@link EurekaServerConfig} specified by <em>eureka.server.props</em> in the * classpath. The eureka client component is also initialized by using the * configuration {@link EurekaInstanceConfig} specified by * <em>eureka.client.props</em>. If the server runs in the AWS cloud, the eureka * server binds it to the elastic ip as specified. * </p> * * @author Karthik Ranganathan, Greg Kim, David Liu * * 負責EurekaServer初始化的類 */ public class EurekaBootStrap implements ServletContextListener { /** * Initializes Eureka, including syncing up with other Eureka peers and publishing the registry. * * @see * javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) */ @Override public void contextInitialized(ServletContextEvent event) { try { initEurekaEnvironment(); initEurekaServerContext(); ServletContext sc = event.getServletContext(); sc.setAttribute(EurekaServerContext.class.getName(), serverContext); } catch (Throwable e) { logger.error("Cannot bootstrap eureka server :", e); throw new RuntimeException("Cannot bootstrap eureka server :", e); } } }
看下注釋 我們可以瞭解到幾個關鍵點:
- eureka server對應的配置類為:EurekaServerConfig
- eureka client對應的配置類為:EurekaInstanceConfig
- EurekaBootStrap implements ServletContextListener, 所以這裡會直接執行contextInitialized方法。
Eureka-Server 環境配置
初始化enviroment
接著近一步往下跟,這裡可以先看 initEurekaEnvironment()
程式碼如下:
protected void initEurekaEnvironment() throws Exception { logger.info("Setting the eureka configuration.."); // 獲取dataCenter資料中心 這裡重點看ConfigurationManager // ConfigurationManager:配置管理器,管理eureka自己所有的配置, // 重點:getConfigInstance裡面使用的是volatile+synchronized+double check模式的單例模式 /** * ConfigurationManager 建立過程:(繼續往後跟讀程式碼) * 1、建立一個ConcurrentCompositeConfiguration例項,這個類代表了所謂的配置,包括eureka需要的所有配置。 * 2、往ConcurrentCompositeConfiguration加入一堆config,然後返回ConfigurationManager例項 * 3、初始化資料中心的配置,如果沒有配置的話就是default data center * 4、初始化eureka 執行的環境,如果沒有配置的話,預設就是test環境 */ String dataCenter = ConfigurationManager.getConfigInstance().getString(EUREKA_DATACENTER); // 初始化資料中心,沒有配置的話 使用DEFAULT data center if (dataCenter == null) { logger.info("Eureka data center value eureka.datacenter is not set, defaulting to default"); ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT); } else { ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter); } // 獲取eureka server執行環境,沒有配置的話預設使用test環境 // 後面讀取配置檔案會根據執行環境讀取,比如eureka-server-test.properties String environment = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT); if (environment == null) { ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST); logger.info("Eureka environment value eureka.environment is not set, defaulting to test"); } }
這裡註釋寫的比較詳細,且這裡有兩個重點:
- getConfigInstance裡面使用的是volatile+synchronized+double check模式的單例模式
- ConfigurationManager 建立過程
getConfigInstance
這裡一個關鍵點 是使用了很經典的double check 單例模式。
這種單例是一種執行緒安全的方式,裡面使用了volatile+synchronized+double check,具體秒在何處 我這裡就不展開講解了,搜尋double check單例模式就會有很多解析文章,這裡直接看程式碼。
static volatile AbstractConfiguration instance = null; /** * Get the current system wide configuration. If there has not been set, it will return a default * {@link ConcurrentCompositeConfiguration} which contains a SystemConfiguration from Apache Commons * Configuration and a {@link DynamicURLConfiguration}. */ public static AbstractConfiguration getConfigInstance() { if (instance == null) { synchronized (ConfigurationManager.class) { if (instance == null) { instance = getConfigInstance(Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_CONFIG)); } } } return instance; }
這裡instance用volatile修飾來保證執行緒之間的可見性,用synchronized來保證執行緒序列化,double check來保證不被單例化。
接著我們就繼續往下跟,看看ConfigurationManager的建立過程。
ConfigurationManager 建立
private static AbstractConfiguration getConfigInstance(boolean defaultConfigDisabled) {
if (instance == null && !defaultConfigDisabled) {
instance = createDefaultConfigInstance();
registerConfigBean();
}
return instance;
}
private static AbstractConfiguration createDefaultConfigInstance() {
ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();
try {
DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME);
} catch (Throwable e) {
logger.warn("Failed to create default dynamic configuration", e);
}
if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) {
SystemConfiguration sysConfig = new SystemConfiguration();
config.addConfiguration(sysConfig, SYS_CONFIG_NAME);
}
if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) {
EnvironmentConfiguration envConfig = new EnvironmentConfiguration();
config.addConfiguration(envConfig, ENV_CONFIG_NAME);
}
ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration();
config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES);
config.setContainerConfigurationIndex(config.getIndexOfConfiguration(appOverrideConfig));
return config;
}
public ConcurrentCompositeConfiguration()
{
clear();
}
public final void clear()
{
fireEvent(EVENT_CLEAR, null, null, true);
configList.clear();
namedConfigurations.clear();
// recreate the in memory configuration
containerConfiguration = new ConcurrentMapConfiguration();
containerConfiguration.setThrowExceptionOnMissing(isThrowExceptionOnMissing());
containerConfiguration.setListDelimiter(getListDelimiter());
containerConfiguration.setDelimiterParsingDisabled(isDelimiterParsingDisabled());
containerConfiguration.addConfigurationListener(eventPropagater);
configList.add(containerConfiguration);
overrideProperties = new ConcurrentMapConfiguration();
overrideProperties.setThrowExceptionOnMissing(isThrowExceptionOnMissing());
overrideProperties.setListDelimiter(getListDelimiter());
overrideProperties.setDelimiterParsingDisabled(isDelimiterParsingDisabled());
overrideProperties.addConfigurationListener(eventPropagater);
fireEvent(EVENT_CLEAR, null, null, false);
containerConfigurationChanged = false;
invalidate();
}
上面程式碼是比較多,如果一行行去摳細節 真的就沒有必要了,這裡我們只是看一些重點的流程,我們上面註釋也寫到過ConfigurationManager的建立過程:
1、建立一個ConcurrentCompositeConfiguration例項,這個類代表了所謂的配置,包括eureka需要的所有配置。
2、往ConcurrentCompositeConfiguration加入一堆config,然後返回ConfigurationManager例項
這裡我是不建議太過於扣細節的,因為往往這些細枝末節的東西會將我們繞進去。
關於ConfigurationManager具體的細節這裡也有兩篇比較好的文章推薦:
- 關於 Eureka 啟動的說明
- 微服務動態配置元件netflix archaius
Eureka-Server 上下文載入
先看程式碼:
protected void initEurekaServerContext() throws Exception {
// 1、載入eureka-server properties檔案中和配置
EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();
// For backward compatibility
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
logger.info("Initializing the eureka client...");
logger.info(eurekaServerConfig.getJsonCodecName());
ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);
// 2、初始化一個ApplicationInfoManager,和第3步建立eureka client相關,後續會講解
ApplicationInfoManager applicationInfoManager = null;
// 3、初始化eureka-server內部的一個eureka-client(用來跟其他的eureka-server節點做註冊和通訊)
// 類的開頭已經說明了:EurekaInstanceConfig其實就是eureka client相關的配置類
if (eurekaClient == null) {
EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())
? new CloudInstanceConfig()
: new MyDataCenterInstanceConfig();
applicationInfoManager = new ApplicationInfoManager(
instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
} else {
applicationInfoManager = eurekaClient.getApplicationInfoManager();
}
// 3、處理註冊相關的事情
PeerAwareInstanceRegistry registry;
if (isAws(applicationInfoManager.getInfo())) {
registry = new AwsInstanceRegistry(
eurekaServerConfig,
eurekaClient.getEurekaClientConfig(),
serverCodecs,
eurekaClient
);
awsBinder = new AwsBinderDelegate(eurekaServerConfig, eurekaClient.getEurekaClientConfig(), registry, applicationInfoManager);
awsBinder.start();
} else {
registry = new PeerAwareInstanceRegistryImpl(
eurekaServerConfig,
eurekaClient.getEurekaClientConfig(),
serverCodecs,
eurekaClient
);
}
// 4、處理peer節點相關的事情
PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(
registry,
eurekaServerConfig,
eurekaClient.getEurekaClientConfig(),
serverCodecs,
applicationInfoManager
);
// 5、完成eureka-server上下文(context)的構建及初始化
serverContext = new DefaultEurekaServerContext(
eurekaServerConfig,
serverCodecs,
registry,
peerEurekaNodes,
applicationInfoManager
);
EurekaServerContextHolder.initialize(serverContext);
serverContext.initialize();
logger.info("Initialized server context");
// Copy registry from neighboring eureka node
// 6、處理一些善後的事情,從相鄰的eureka節點拷貝註冊資訊
int registryCount = registry.syncUp();
registry.openForTraffic(applicationInfoManager, registryCount);
// Register all monitoring statistics.
// 7、註冊所有的監控統計項
EurekaMonitors.registerAllStats();
}
程式碼有點長,載入context資訊分為了上面註釋的好幾步,程式碼註釋都有寫
載入eureka-server properties檔案中和配置
EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();
private static final DynamicStringProperty EUREKA_PROPS_FILE = DynamicPropertyFactory.getInstance().getStringProperty("eureka.server.props","eureka-server");
public DefaultEurekaServerConfig() {
init();
}
private void init() {
String env = ConfigurationManager.getConfigInstance().getString(
EUREKA_ENVIRONMENT, TEST);
ConfigurationManager.getConfigInstance().setProperty(
ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env);
String eurekaPropsFile = EUREKA_PROPS_FILE.get();
try {
// ConfigurationManager
// .loadPropertiesFromResources(eurekaPropsFile);
ConfigurationManager
.loadCascadedPropertiesFromResources(eurekaPropsFile);
} catch (IOException e) {
logger.warn(
"Cannot find the properties specified : {}. This may be okay if there are other environment "
+ "specific properties or the configuration is installed with a different mechanism.",
eurekaPropsFile);
}
}
public static void loadCascadedPropertiesFromResources(String configName) throws IOException {
Properties props = loadCascadedProperties(configName);
if (instance instanceof AggregatedConfiguration) {
ConcurrentMapConfiguration config = new ConcurrentMapConfiguration();
config.loadProperties(props);
((AggregatedConfiguration) instance).addConfiguration(config, configName);
} else {
ConfigurationUtils.loadProperties(props, instance);
}
}
首先我們看下EurekaServerConfig
:
裡面包含好多getxxx方法,看一下具體實現:
其中configInstance是DynamicPropertyFactory
物件。EurekaServerConfig,這是個介面,這裡面有一堆getXXX()的方法,包含了eureka server需要使用的所有的配置,都可以通過這個介面來獲取。
想象一下,eureka-sever.properties檔案裡,都是一個一個的key=value的很多的配置項,肯定是將這些key-value格式的配置項載入到記憶體的Properties物件去存放,Map。一般來說,如果讓我們自己來設計這個讀取properties檔案的配置的程式碼,也許我們就是做到將配置載入到Properties物件中就結束了。
EurekaServerConfig,代表了eureka-server需要的所有的配置項,通過介面定義了大量的方法,讓你可以從這裡獲取所有你需要的配置
DefaultEurekaServerConfig
就是上面EurekaServerConfig
的實現類,建立例項的時候,會執行一個init()方法,在這個方法中,就會完成eureka-server.properties檔案中的配置項的載入。EUREKA_PROPS_FILE,對應著要載入的eureka的配置檔案的名字。
將加載出來的Properties中的配置項都放到ConfigurationManager中去,由這個ConfigurationManager來管理
比如說eureka-server那個工程裡,就有一個src/main/resources/eureka-server.properties檔案,只不過裡面是空的,全部都用了預設的配置
DefaultEurekaServerConfig.init()方法中,會將eureka-server.properties檔案中的配置加載出來,都放到ConfdigurationManager中去,然後在DefaultEurekaServerConfig的各種獲取配置項的方法中,配置項的名字是在各個方硬編碼的,是從一個DynamicPropertyFactory裡面去獲取的,你可以認為DynamicPropertyFactory是從ConfigurationManager那兒來的,因為ConfigurationManager中都包含了加載出來的配置了,所以DynamicPropertyFactory裡,也可以獲取到所有的配置項
在從DynamicPropertyFactory中獲取配置項的時候,如果你沒配置,那麼就用預設值,全部都給你弄好了各個配置項的預設值,相當於所有的配置項的預設值,在DefaultEurekaServerConfig的各個方法中,都可以看到,如果你沒配置,那麼就用這裡的預設值就可以了
載入eureka-server.properties的過程:
(1)建立了一個DefaultEurekaServerConfig物件
(2)建立DefaultEurekaServerConfig物件的時候,在裡面會有一個init方法
(3)先是將eureka-server.properties中的配置載入到了一個Properties物件中,然後將Properties物件中的配置放到ConfigurationManager中去,此時ConfigurationManager中去就有了所有的配置了
(4)然後DefaultEurekaServerConfig提供的獲取配置項的各個方法,都是通過硬編碼的配置項名稱,從DynamicPropertyFactory中獲取配置項的值,DynamicPropertyFactory是從ConfigurationManager那兒來的,所以也包含了所有配置項的值
(5)在獲取配置項的時候,如果沒有配置,那麼就會有預設的值,全部屬性都是有預設值的
申明
本文章首發自本人部落格:https://www.cnblogs.com/wang-meng 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!
感興趣的小夥伴可關注個人公眾號:壹枝花算不算浪漫
相關推薦
【一起學原始碼-微服務】Nexflix Eureka 原始碼二:EurekaServer啟動之配置檔案載入以及面向介面的配置項讀取
前言 上篇文章已經介紹了 為何要讀netflix eureka原始碼了,這裡就不再概述,下面開始正式原始碼解讀的內容。 如若轉載 請標明來源:一枝花算不算浪漫 程式碼總覽 還記得上文中,我們通過web.xml找到了eureka server入口的類EurekaBootStrap,這裡我們就先來簡單地看下: /
【一起學原始碼-微服務】Nexflix Eureka 原始碼三:EurekaServer啟動之EurekaServer上下文EurekaClient建立
前言 上篇文章已經介紹了 Eureka Server 環境和上下文初始化的一些程式碼,其中重點講解了environment初始化使用的單例模式,以及EurekaServerConfigure基於介面對外暴露配置方法的設計方式。這一講就是講解Eureka Server上下文初始化剩下的內容:Eureka Cli
【一起學原始碼-微服務】Nexflix Eureka 原始碼六:在眼花繚亂的程式碼中,EurekaClient是如何註冊的?
前言 上一講已經講解了EurekaClient的啟動流程,到了這裡已經有6篇Eureka原始碼分析的文章了,看了下之前的文章,感覺程式碼成分太多,會影響閱讀,後面會只擷取主要的程式碼,加上註釋講解。 這一講看的是EurekaClient註冊的流程,當然也是一塊核心,標題為什麼會寫上眼花繚亂呢?關於Eureka
【一起學原始碼-微服務】Nexflix Eureka 原始碼七:通過單元測試來Debug Eureka註冊過程
前言 上一講eureka client是如何註冊的,一直跟到原始碼傳送http請求為止,當時看eureka client註冊時如此費盡,光是找一個regiter的地方就找了半天,那麼client端傳送了http請求給server端,server端是如何處理的呢? 帶著這麼一個疑問 就開始今天原始碼的解讀了。
【一起學原始碼-微服務】Nexflix Eureka 原始碼八:EurekaClient登錄檔抓取 精妙設計分析!
前言 前情回顧 上一講 我們通過單元測試 來梳理了EurekaClient是如何註冊到server端,以及server端接收到請求是如何處理的,這裡最重要的關注點是登錄檔的一個數據結構:ConcurrentHashMap<String, Map<String, Lease<InstanceI
【一起學原始碼-微服務】Nexflix Eureka 原始碼九:服務續約原始碼分析
前言 前情回顧 上一講 我們講解了服務發現的相關邏輯,所謂服務發現 其實就是登錄檔抓取,服務例項預設每隔30s去註冊中心抓取一下注冊表增量資料,然後合併本地登錄檔資料,最後有個hash對比的操作。 本講目錄 今天主要是看下服務續約的邏輯,服務續約就是client端給server端傳送心跳檢測,告訴對方我還活著
【一起學原始碼-微服務】Nexflix Eureka 原始碼十:服務下線及例項摘除,一個client下線到底多久才會被其他例項感知?
前言 前情回顧 上一講我們講了 client端向server端傳送心跳檢查,也是預設每30鍾傳送一次,server端接收後會更新登錄檔的一個時間戳屬性,然後一次心跳(續約)也就完成了。 本講目錄 這一篇有兩個知識點及一個疑問,這個疑問是在工作中真真實實遇到過的。 例如我有服務A、服務B,A、B都註冊在同一個註
【一起學原始碼-微服務】Nexflix Eureka 原始碼十一:EurekaServer自我保護機制竟然有這麼多Bug?
前言 前情回顧 上一講主要講了服務下線,已經註冊中心自動感知宕機的服務。 其實上一講已經包含了很多EurekaServer自我保護的程式碼,其中還發現了1.7.x(1.9.x)包含的一些bug,但這些問題在master分支都已修復了。 服務下線會將服務例項從登錄檔中刪除,然後放入到recentQueue中,下
【一起學原始碼-微服務】Nexflix Eureka 原始碼十二:EurekaServer叢集模式原始碼分析
前言 前情回顧 上一講看了Eureka 註冊中心的自我保護機制,以及裡面提到的bug問題。 哈哈 轉眼間都2020年了,這個系列的文章從12.17 一直寫到現在,也是不容易哈,每天持續不斷學習,輸出部落格,這一段時間確實收穫很多。 今天在公司給組內成員分享了Eureka原始碼剖析,反響效果還可以,也算是感覺收
【一起學原始碼-微服務】Nexflix Eureka 原始碼十三:Eureka原始碼解讀完結撒花篇~!
前言 想說的話 【一起學原始碼-微服務-Netflix Eureka】專欄到這裡就已經全部結束了。 實話實說,從最開始Eureka Server和Eureka Client初始化的流程還是一臉悶逼,到現在Eureka各種操作都瞭然於心了。 本專欄從12.17開始寫,一直到今天12.30(文章在平臺是延後釋出的
【一起學原始碼-微服務】Ribbon 原始碼一:Ribbon概念理解及Demo除錯
前言 前情回顧 前面文章已經梳理清楚了Eureka相關的概念及原始碼,接下來開始研究下Ribbon的實現原理。 我們都知道Ribbon在spring cloud中擔當負載均衡的角色, 當兩個Eureka Client互相呼叫的時候,Ribbon能夠做到呼叫時的負載,保證多節點的客戶端均勻接收請求。(這個有點類
【一起學原始碼-微服務】Ribbon 原始碼二:通過Debug找出Ribbon初始化流程及ILoadBalancer原理分析
前言 前情回顧 上一講講了Ribbon的基礎知識,通過一個簡單的demo看了下Ribbon的負載均衡,我們在RestTemplate上加了@LoadBalanced註解後,就能夠自動的負載均衡了。 本講目錄 這一講主要是繼續深入RibbonLoadBalancerClient和Ribbon+Eureka整合的
【一起學原始碼-微服務】Ribbon 原始碼三:Ribbon與Eureka整合原理分析
前言 前情回顧 上一篇講了Ribbon的初始化過程,從LoadBalancerAutoConfiguration 到RibbonAutoConfiguration 再到RibbonClientConfiguration,我們找到了ILoadBalancer預設初始化的物件等。 本講目錄 這一講我們會進一步往下
【一起學原始碼-微服務】Ribbon 原始碼四:進一步探究Ribbon的IRule和IPing
前言 前情回顧 上一講深入的講解了Ribbon的初始化過程及Ribbon與Eureka的整合程式碼,與Eureka整合的類就是DiscoveryEnableNIWSServerList,同時在DynamicServerListLoadBalancer中會呼叫PollingServerListUpdater 進
【一起學原始碼-微服務】Ribbon原始碼五:Ribbon原始碼解讀彙總篇~
前言 想說的話 【一起學原始碼-微服務-Ribbon】專欄到這裡就已經全部結束了,共更新四篇文章。 Ribbon比較小巧,這裡是直接 讀的spring cloud 內嵌封裝的版本,裡面的各種configuration確實有點繞,不過看看第三講Ribbon初始化的過程總結圖就會清晰很多。 緊接著會繼續整理學習F
【一起學原始碼-微服務】Feign 原始碼一:原始碼初探,通過Demo Debug Feign原始碼
前言 前情回顧 上一講深入的講解了Ribbon的初始化過程及Ribbon與Eureka的整合程式碼,與Eureka整合的類就是DiscoveryEnableNIWSServerList,同時在DynamicServerListLoadBalancer中會呼叫PollingServerListUpdater 進
【一起學原始碼-微服務】Feign 原始碼二:Feign動態代理構造過程
前言 前情回顧 上一講主要看了@EnableFeignClients中的registerBeanDefinitions()方法,這裡面主要是 將EnableFeignClients註解對應的配置屬性注入,將FeignClient註解對應的屬性注入。 最後是生成FeignClient對應的bean,注入到Spr
【一起學原始碼-微服務】Feign 原始碼三:Feign結合Ribbon實現負載均衡的原理分析
前言 前情回顧 上一講我們已經知道了Feign的工作原理其實是在專案啟動的時候,通過JDK動態代理為每個FeignClinent生成一個動態代理。 動態代理的資料結構是:ReflectiveFeign.FeignInvocationHandler。其中包含target(裡面是serviceName等資訊)和d
【一起學原始碼-微服務】Hystrix 原始碼一:Hystrix基礎原理與Demo搭建
說明 原創不易,如若轉載 請標明來源! 歡迎關注本人微信公眾號:壹枝花算不算浪漫 更多內容也可檢視本人部落格:一枝花算不算浪漫 前言 前情回顧 上一個系列文章講解了Feign的原始碼,主要是Feign動態代理實現的原理,及配合Ribbon實現負載均衡的機制。 這裡我們講解一個新的元件Hystrix,也是和Fe
【一起學原始碼-微服務】Hystrix 原始碼二:Hystrix核心流程:Hystix非降級邏輯流程梳理
說明 原創不易,如若轉載 請標明來源! 歡迎關注本人微信公眾號:壹枝花算不算浪漫 更多內容也可檢視本人部落格:一枝花算不算浪漫 前言 前情回顧 上一講我們講了配置了feign.hystrix.enabled=true之後,預設的Targeter就會構建成HystrixTargter, 然後通過對應的Hystr