主頁 > 後端開發 > springboot啟動流程 (1) 流程概覽

springboot啟動流程 (1) 流程概覽

2023-06-16 07:36:15 後端開發

本文將通過閱讀原始碼方式分析SpringBoot應用的啟動流程,不涉及Spring啟動部分(有相應的文章介紹),

本文不會對各個流程做展開分析,后續會有文章介紹詳細流程,

SpringApplication類

應用啟動入口

使用以下方式啟動一個SpringBoot應用:

@SpringBootApplication
public class SpringBootDemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(SpringBootDemoApplication.class, args);
  }
}

run方法

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		// 獲取應用env
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		// 列印banner
		Banner printedBanner = printBanner(environment);
		// 創建ApplicationContext
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		// 一些準備作業
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		// refresh ApplicationContext
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		// 呼叫listener
		listeners.started(context);
		// 呼叫ApplicationRunner和CommandLineRunner
		callRunners(context, applicationArguments);
	} catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		listeners.running(context);
	} catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

獲取應用env

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// 創建StandardServletEnvironment, 會初始化四個PropertySource:
	// servletConfigInitParams, servletContextInitParams, systemProperties, systemEnvironment
	// 比如-Dserver.port=8888會在systemProperties中
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	// 添加defaultProperties和命令列配置引數即CommandLinePropertySource
	// 通常都沒有這兩個配置
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	// 使用ConfigurationPropertySourcesPropertySource封裝并暴露所有的PropertySource集
	ConfigurationPropertySources.attach(environment);
	// 添加ApplicationEnvironmentPreparedEvent事件并觸發multicastEvent加載應用組態檔
	listeners.environmentPrepared(environment);
	// 將spring.main.xx配置加載到SpringApplication物件
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

加載組態檔的入口在ConfigFileApplicationListener類中:

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
	addPropertySources(environment, application.getResourceLoader());
}

protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
	// 添加RandomValuePropertySource
	RandomValuePropertySource.addToEnvironment(environment);
	// 加載組態檔
	new Loader(environment, resourceLoader).load();
}

加載組態檔的原始碼較多,此處不做記錄,簡單梳理一下流程:

  1. 加載active profile組態檔
    • 如果配置了spring.config.additional-location或spring.config.location引數,會使用它們作為組態檔,如果這兩個引數值是目錄,則會從這兩個目錄下查找組態檔
    • 默認從classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/目錄下查找application-xx.properties或application-xx.yml檔案
    • 使用PropertiesPropertySourceLoader和YamlPropertySourceLoader決議組態檔
    • 會將配置引數封裝成OriginTrackedMapPropertySource型別物件,使用applicationConfig: [classpath:/application-dev.yml]之類的字串作為PropertySource的名稱
  2. 加載默認的application.properties或application.yml檔案
  3. 決議出來的所有PropertySource都會添加到environment的propertySources中,propertySources是一個MutablePropertySources物件,管理著所有的PropertySource集,在這個程序中,添加的先后順序決定了配置的優先級

創建ApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				// AnnotationConfigServletWebServerApplicationContext類
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				// AnnotationConfigReactiveWebServerApplicationContext類
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				// AnnotationConfigApplicationContext類
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		} catch (ClassNotFoundException ex) {
			throw new IllegalStateException("Unable create a default ApplicationContext", ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

prepareContext

private void prepareContext(
		ConfigurableApplicationContext context, ConfigurableEnvironment environment,
		SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments,
		Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	// Apply any ApplicationContextInitializers to the context before it is refreshed.
	// ApplicationContextInitializers集是在創建SpringApplication物件的時候初始化的
	applyInitializers(context);
	// 觸發contextPrepared事件
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// 獲取BeanFactory并注冊必要的Bean
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	// 注冊啟動引數
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	// 注冊banner printer
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	// 設定是否允許Bean覆寫,使用spring.main.allowBeanDefinitionOverriding引數配置
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// Load the sources
	Set<Object> sources = getAllSources();
	// 將SpringApplication.run(Xxx.class, args)方法傳入的Class注冊到容器
	// 使用AnnotatedBeanDefinitionReader.register(Class<?>...)方法注冊啟動類
	load(context, sources.toArray(new Object[0]));
	// 觸發contextLoaded事件
	listeners.contextLoaded(context);
}

refreshApplicationContext

protected void refresh(ConfigurableApplicationContext applicationContext) {
	applicationContext.refresh();
}

呼叫的是ServletWebServerApplicationContext的refresh方法:

public final void refresh() throws BeansException, IllegalStateException {
	try {
		super.refresh();
	} catch (RuntimeException ex) {
		// 關閉web server
		WebServer webServer = this.webServer;
		if (webServer != null) {
			webServer.stop();
		}
		throw ex;
	}
}

絕大多數的refresh邏輯都在AbstractApplicationContext類里面,ServletWebServerApplicationContext中會在onRefresh階段創建webServer:

protected void onRefresh() {
	super.onRefresh();
	try {
		createWebServer();
	} catch (Throwable ex) {
		throw new ApplicationContextException("Unable to start web server", ex);
	}
}

呼叫ApplicationRunner和CommandLineRunner

private void callRunners(ApplicationContext context, ApplicationArguments args) {
	List<Object> runners = new ArrayList<>();
	runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
	runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
	AnnotationAwareOrderComparator.sort(runners);
	for (Object runner : new LinkedHashSet<>(runners)) {
		if (runner instanceof ApplicationRunner) {
			callRunner((ApplicationRunner) runner, args);
		}
		if (runner instanceof CommandLineRunner) {
			callRunner((CommandLineRunner) runner, args);
		}
	}
}

SpringBootApplication注解

指示一個配置類,該類宣告一個或多個@Bean方法,并觸發自動配置和組件掃描,這是一個方便的注解,相當于宣告@Configuration、@EnableAutoConfiguration和@ComponentScan注解,

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	/**
	 * Base packages to scan for annotated components. Use scanBasePackageClasses
	 * for a type-safe alternative to String-based package names.
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	/**
	 * Type-safe alternative to scanBasePackages for specifying the packages to
	 * scan for annotated components. The package of each class specified will be scanned.
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

	/**
	 * The BeanNameGenerator class to be used for naming detected components
	 * within the Spring container.
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	/**
	 * Specify whether @Bean methods should get proxied in order to enforce
	 * bean lifecycle behavior, e.g. to return shared singleton bean instances even in
	 * case of direct @Bean method calls in user code. This feature requires
	 * method interception, implemented through a runtime-generated CGLIB subclass which
	 * comes with limitations such as the configuration class and its methods not being
	 * allowed to declare final.
	 */
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;
}

SpringBootConfiguration注解

指示一個類提供Spring Boot application @Configuration功能,可以替代Spring的標準@Configuration注解,以便可以自動找到配置類,

應用程式應該只標注一個@SpringBootConfiguration,大多數SpringBoot應用程式將從@SpringBootApplication繼承它,

@Configuration
public @interface SpringBootConfiguration {

	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;
}

EnableAutoConfiguration注解

啟用SpringBoot自動裝配功能,嘗試猜測和配置可能需要的組件Bean,

自動裝配類通常是根據類路徑和定義的Bean來應用的,例如,如果類路徑上有tomcat-embedded.jar,那么可能需要一個TomcatServletWebServerFactory(除非已經定義了自己的Servlet WebServerFactory Bean),

自動裝配試圖盡可能地智能化,并將隨著開發者定義自己的配置而取消自動裝配相沖突的配置,開發者可以使用exclude()排除不想使用的配置,也可以通過spring.autoconfig.exclude屬性排除這些配置,自動裝配總是在用戶定義的Bean注冊之后應用,

用@EnableAutoConfiguration注解標注的類所在包具有特定的意義,通常用作默認掃描的包,通常建議將@EnableAutoConfiguration(如果沒有使用@SpringBootApplication注解)放在根包中,以便可以搜索所有子包和類,

自動裝配類是普通的Spring @Configuration類,使用SpringFactoriesLoader機制定位,通常使用@Conditional方式裝配,最常用的是@ConditionalOnClass和@ConditionalOnMissingBean注解,

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * 當類路徑下沒有指定的類時,可以使用這個屬性指定排除的類
	 */
	String[] excludeName() default {};
}

AutoConfigurationPackage注解

Registers packages with AutoConfigurationPackages. When no base packages or base package classes are specified, the package of the annotated class is registered.

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

	String[] basePackages() default {};

	Class<?>[] basePackageClasses() default {};
}

AutoConfigurationImportSelector類

DeferredImportSelector介面的實作類,處理自動裝配,匯出所有需要自動裝配的類,

創建WebServer

SpringBoot會在onRefresh階段創建webServer,首先從spring容器獲取ServletWebServerFactory,然后呼叫getWebServer方法創建webServer,

getWebServer方法需要傳入ServletContextInitializer集來初始化ServletContext,

@FunctionalInterface
public interface ServletContextInitializer {

	void onStartup(ServletContext servletContext) throws ServletException;
}

我們開發者如果需要使用ServletContextInitializer來初始化ServletContext的話,也可以撰寫一個實作類,然后將其注冊到spring容器即可,

另外,SpringBoot還會自動裝配DispatcherServletAutoConfiguration類,這個類會創建DispatcherServlet和DispatcherServletRegistrationBean,DispatcherServlet是SpringWebMvc的最核心組件,DispatcherServletRegistrationBean實作了ServletContextInitializer介面,可以將DispatcherServlet注冊到ServletContext,以TomcatServletWebServerFactory為例,這個類會通過TomcatStarter來呼叫所有的ServletContextInitializer,TomcatStarter實作了ServletContainerInitializer介面,Tomcat的ServletContext在啟動階段會呼叫ServletContainerInitializer的onStartup方法來初始化Servlet容器,

SpringBoot啟動流程

  • 初始化environment應用配置引數:servletConfigInitParams, servletContextInitParams, systemProperties, systemEnvironment及組態檔等
  • 創建ApplicationContext物件,SpringBoot應用默認使用的是AnnotationConfigServletWebServerApplicationContext類
  • prepareContext階段:觸發一些事件,將啟動類注冊到Spring容器
  • refresh階段:掃描應用組件,自動裝配
  • onRefresh階段:創建并初始化WebServer
  • 呼叫ApplicationRunner和CommandLineRunner

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555239.html

標籤:其他

上一篇:Scala基本語法

下一篇:返回列表

標籤雲
其他(161032) Python(38230) JavaScript(25496) Java(18240) C(15237) 區塊鏈(8270) C#(7972) AI(7469) 爪哇(7425) MySQL(7253) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4594) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2435) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) 功能(1967) HtmlCss(1966) Web開發(1951) C++(1940) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • springboot啟動流程 (1) 流程概覽

    本文將通過閱讀原始碼方式分析SpringBoot應用的啟動流程,不涉及Spring啟動部分(有相應的文章介紹)。 本文不會對各個流程做展開分析,后續會有文章介紹詳細流程。 # SpringApplication類 ## 應用啟動入口 使用以下方式啟動一個SpringBoot應用: ```java @S ......

    uj5u.com 2023-06-16 07:36:15 more
  • Scala基本語法

    # scala的基本語法 ## 注釋 對于scala的注釋,簡而言之就是一句話,和java的注釋一模一樣 基本語法 ``` (1)單行注釋:// (2)多行注釋:/* */ (3)檔案注釋:/** * */ ``` 代碼示例: ```Scala package com.doitedu.demo01 ......

    uj5u.com 2023-06-16 07:30:15 more
  • C++面試八股文:在C++中,有哪些可執行體?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第14面: > 面試官:在C++中,有哪些可執行體? > > 二師兄:可執行體? > > 面試官:也就是可呼叫物件。 > > 二師兄:讓我想一想。函式、函式指標、類的靜態方法、類的成員方法、仿函式、lambda運算式。 > > 面試官:能說一說他們之 ......

    uj5u.com 2023-06-15 08:10:42 more
  • Set 介面及其常用方法

    Set 介面是 Collection 介面的一個子介面。Set 介面的實作類不會包含重復的元素,并且最多只能有一個 null 元素。當嘗試添加重復元素時,添加操作將被忽略。Set 介面取出元素的順序和添加元素的順序不一致(但是每次取出的順序是固定的),即無法通過索引訪問 Set 中的元素。 ......

    uj5u.com 2023-06-15 08:10:38 more
  • Go語言中的結構體:靈活性與可擴展性的重要角色

    # 1. 引言 結構體是Go語言中重要且靈活的概念之一。結構體的使用使得我們可以定義自己的資料型別,并將不同型別的欄位組合在一起,實作更靈活的資料結構。本文旨在深入介紹Go語言中的結構體,揭示其重要性和靈活性,并向讀者展示結構體支持的眾多特性,展示其強大之處。 # 2. 什么是結構體? 在Go語言中 ......

    uj5u.com 2023-06-15 08:10:33 more
  • 【python基礎】函式-初識函式

    函式是帶名字的代碼塊,用于完成具體的作業,無需反復撰寫完成該作業的代碼。之前我們接觸過print函式,資料型別轉換中的int函式、str函式,還有串列中的append函式、pop函式、remove函式,以及字典中的keys函式、values函式等等,其實在正式學習函式之前,我們已經接觸了函式,只不過 ......

    uj5u.com 2023-06-15 08:10:23 more
  • rocketMQ訊息佇列簡介及其實體

    一、RocketMQ 核心的四大組件: Producer:就是訊息生產者,可以集群部署。它會先和 NameServer 集群中的隨機一臺建立長連接,得知當前要發送的 Topic 存在哪臺 Broker Master上,然后再與其建立長連接,支持多種負載平衡模式發送訊息。 Consumer:訊息消費者 ......

    uj5u.com 2023-06-15 08:10:11 more
  • jvm垃圾回收及記憶體模型

    1、了解垃圾回收之前,必須先了解記憶體模型 2、垃圾回收區域 a、 首先要標記垃圾,找出垃圾 b、Java垃圾回收(一)_java 垃圾回收_頭發慢點掉的小馬的博客-CSDN博客 垃圾回收器 方法區不需要連續的記憶體,可以選擇固定大小或者可擴展。并且還可以選擇不實作垃圾收集。相對而言,垃圾收集行為在這個 ......

    uj5u.com 2023-06-15 08:09:55 more
  • Dubbo負載均衡策略之 一致性哈希

    本文主要講解了一致性哈希演算法的原理以及其存在的資料傾斜的問題,然后引出解決資料傾斜問題的方法,最后分析一致性哈希演算法在Dubbo中的使用。通過這篇文章,可以了解到一致性哈希演算法的原理以及這種演算法存在的問題和解決方案。 ......

    uj5u.com 2023-06-15 08:09:44 more
  • Go 語言之 SQLX 高級操作 sqlx.In

    # Go 語言之 SQLX 高級操作 sqlx.In ## sqlx.In 介紹 `sqlx` is a package for Go which provides a set of extensions on top of the excellent built-in `database/sql` ......

    uj5u.com 2023-06-15 08:09:40 more