主頁 > 後端開發 > Spring原始碼:Bean生命周期(五)

Spring原始碼:Bean生命周期(五)

2023-05-16 18:01:37 後端開發

前言

在上一篇文章中,我們深入探討了 Spring 框架中 Bean 的實體化程序,該程序包括從 Bean 定義中加載當前類、尋找所有實作了 InstantiationAwareBeanPostProcessor 介面的類并呼叫實體化前的方法、進行實體化、呼叫 applyMergedBeanDefinitionPostProcessors 方法等多個步驟,最終生成了一個真正的 Bean 實體,但是,這個 Bean 實體還沒有被初始化和注入屬性,還不能真正發揮作用,

在今天的文章中,我們將深入探討 Bean 的屬性注入和初始化流程,從而使其成為一個真正意義上的 Bean,這個程序包括屬性注入、Aware 介面回呼、BeanPostProcessor 的前置和后置處理等多個步驟,通過本文的學習,讀者將能夠更深入地了解 Spring 框架中 Bean 的屬性注入和初始化程序,為后續的學習和實踐打下堅實的基礎,

populateBean

在 Spring 框架中,屬性注入是 Bean 初始化程序中的一個重要環節,在 Bean 實體化完成后,Spring 框架會根據 Bean 定義中的屬性設定進行屬性注入,同時還會呼叫一些 Aware 介面回呼方法,以及一些 BeanPostProcessor 的前置和后置處理方法,最終完成 Bean 的初始化程序,好的,拋去不用看的,我們來看下剩下的原始碼:

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	}
......
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			// MutablePropertyValues是PropertyValues具體的實作類
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				// 這里會呼叫AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,會直接給物件中的屬性賦值
				// AutowiredAnnotationBeanPostProcessor內部并不會處理pvs,直接回傳了
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		......

		// 如果當前Bean中的BeanDefinition中設定了PropertyValues,那么最終將是PropertyValues中的值,覆寫@Autowired
		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

PropertyValues

在 Spring 框架中,PropertyValues 物件是從 Bean 定義中獲取的,而我們自己定義的 Bean 并沒有這個屬性值,一般情況下,這一步會被跳過,但如果需要注入屬性值,我們可以通過實作 MergedBeanDefinitionPostProcessor 介面的 postProcessMergedBeanDefinition 方法來對 Bean 定義進行修改,從而添加需要注入的屬性值,

具體來說,我們可以定義一個實作了 MergedBeanDefinitionPostProcessor 介面的類,比如下面這個例子::

@Component
public class MyInstantiationAwareBeanPostProcessors implements InstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		if (beanName.equals("userService")) {
			beanDefinition.setPropertyValues(new MutablePropertyValues().add("orderService", new First()));
		}
	}
}

在這個例子中,我們判斷如果 Bean 的名稱是 "userService",則添加一個名為 "orderService" 的屬性,并將其值設定為 First 類的一個實體,需要注意的是,為了能夠正常注入屬性值,我們需要在 Bean 中定義一個名為 "setOrderService" 的 setter 方法,這樣就可以注入進去,當然我寫的這個是報錯的狀態,這樣大家可以找到他是在哪里進行呼叫的,

autowireByName/autowireByType

講解之前,我先宣告一下他跟我們的@autowired注解沒有半毛錢關系,除了上面一種我們人為干預的,還有一種Spring自帶的方式,在我們配置類中:

	@Bean(autowire = Autowire.BY_NAME)
	public UserService userService(){
		return new UserService();
	}

這樣定義時,他就會自動掃描你這個當前類中所有的set方法,是所有的、而且不區分的,這里以autowireByName為例講解,autowireByType類似:

	protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		// 當前Bean中能進行自動注入的屬性名
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		// 遍歷每個屬性名,并去獲取Bean物件,并設定到pvs中
		for (String propertyName : propertyNames) {
			if (containsBean(propertyName)) {
				Object bean = getBean(propertyName);
				pvs.add(propertyName, bean);
				// 記錄一下propertyName對應的Bean被beanName給依賴了
				registerDependentBean(propertyName, beanName);
				if (logger.isTraceEnabled()) {
					logger.trace("Added autowiring by name from bean name '" + beanName +
							"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
							"' by name: no matching bean found");
				}
			}
		}
	}
  1. unsatisfiedNonSimpleProperties:找到所有set方法
  2. getBean:按照set方法名字獲取bean
  3. pvs.add(propertyName, bean):設定到MutablePropertyValues屬性中,不是對我們的bean進行屬性注入

那有些同學可能會想到了,為什么Spring已經默認提供了一套注入方式還有弄一個@autowired注解呢?主要是因為它們各自有不同的優點和適用場景,

默認的注入方式非常靈活,它會遍歷 Bean 中所有的 setter 方法,對每個屬性進行注入,從而實作自動裝配,這種方式適用于大多數情況,因為它能夠自動識別并注入所有需要的依賴項,并且不需要進行任何額外的配置,

而 @Autowired 注解則提供了更加精細的控制,它可以指定需要注入的屬性或方法,并且還可以指定注入的方式、名稱、是否必須等屬性,這種方式適用于需要更加精細的控制和配置的情況,@Autowired 注解是一個可插拔的組件,它只有在 Spring 容器啟動時掃描到該注解時才能夠進行自動裝配,如果我們使用 XML 配置的方式啟動 Spring 容器,需要在組態檔中添加 context:component-scan 元素來開啟自動掃描功能,否則即使寫了 @Autowired 注解也不會進行注入,

postProcessProperties

這一步將會對@autowired注解進行屬性注入,其他的不看,這里只看下AutowiredAnnotationBeanPostProcessor對屬性或者方法的注入:

	private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		// 如果一個Bean的型別是String...,那么則根本不需要進行依賴注入
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			// 遍歷targetClass中的所有Field
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				// field上是否存在@Autowired、@Value、@Inject中的其中一個
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					// static filed不是注入點,不會進行自動注入
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}

					// 構造注入點
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

			// 遍歷targetClass中的所有Method
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {

				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				// method上是否存在@Autowired、@Value、@Inject中的其中一個
				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					// static method不是注入點,不會進行自動注入
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					// set方法最好有入參
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return InjectionMetadata.forElements(elements, clazz);
	}
  1. 如果一個Bean的型別是String...,那么則根本不需要進行依賴注入
  2. 遍歷targetClass中的所有Field,static filed不是注入點,不會進行自動注入
  3. 遍歷targetClass中的所有Method,static method不是注入點,不會進行自動注入
  4. 上面的注入點構造好后,會在外層直接invoke呼叫注入

這里強調一下在對方法注入點進行注入時,會先判斷一下是否有PropertyValues,如果有的話則跳過注入,AutowiredMethodElement原始碼如下:

		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			// 如果pvs中已經有當前注入點的值了,則跳過注入
			if (checkPropertySkipping(pvs)) {
				return;
			}
			......
		}

applyPropertyValues

直接應用PropertyValues注入屬性,可以看到這一步在我們的@autowired決議注入之后,如果你有的屬性欄位已經被@autowired注入了,但是又有一個PropertyValues那么這個set方法會把你的@Autowired之前注入進去的物件值覆寫,原始碼很多為了篇幅就不看了,知道這個方法是干啥的就行,

initializeBean

屬性填充完之后,終于進入到了初始化階段,為什么需要初始化這一步呢?這是對bean的最終處理,該方法回傳的物件才是Spring管理的最終物件,Spring AOP就是對初始化這一步做 的擴展,

	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;

		// 初始化前
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		// 初始化
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}

		// 初始化后 AOP
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

invokeAwareMethods

該方法就是Aware介面的實作

	private void invokeAwareMethods(String beanName, Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

applyBeanPostProcessorsBeforeInitialization

初始化前的類處理,我們主講兩個類:ApplicationContextAwareProcessor、

InitDestroyAnnotationBeanPostProcessor通過這兩個類看看可以初始化前我們可以做哪些內容:

ApplicationContextAwareProcessor

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
				bean instanceof ApplicationStartupAware)) {
			return bean;
		}
......
			// 執行aware方法
			invokeAwareInterfaces(bean);
		}
		return bean;
	}

初始化前會判斷當前是否是某個Aware類,那么則執行aware方法進行回呼,

InitDestroyAnnotationBeanPostProcessor

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		LifecycleMetadata metadata = https://www.cnblogs.com/guoxiaoyu/p/findLifecycleMetadata(bean.getClass());
		try {
			metadata.invokeInitMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
			throw new BeanCreationException(beanName,"Invocation of init method failed", ex.getTargetException());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
		}
		return bean;
	}
  1. findLifecycleMetadata:好奇的小伙伴可以看下這個方法,他會構造@PostConstruct、@PreDestroy執行點
  2. metadata.invokeInitMethods:執行帶有@PostConstruct方法

invokeInitMethods

	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			......
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}
  1. 如果當前類實作了InitializingBean介面,那么執行afterPropertiesSet方法進行初始化
  2. initMethodName:如果當前類指定了初始方法,那么直接invoke執行

applyBeanPostProcessorsAfterInitialization

	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;

		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

執行完postProcessAfterInitialization方法后,那么這個物件終于初始化成功了

總結

今天我們主講bean的初始化,主要流程如下:

  1. 屬性注入,執行@autowired、PropertyValues注入等
  2. 初始化前置方法,執行@PostConstruct方法、回呼Aware介面等
  3. 初始化,呼叫afterPropertiesSet或者initMethod
  4. 初始化后置方法

最后一節我們會講bean的銷毀,那么bean的生命周期系列文章會結束,實際上 Spring 框架還有很多其他的功能和特性,例如 AOP、事務管理、Web 開發等等,博主還會進行對Spring系列繼續更新,請大家繼續跟緊學習,

公眾號 ps:以上內容,純屬個人見解,有任何問題下方評論!關注博主公眾號,原始碼專題、面試精選、AI最新擴展等你來看!原創撰寫不易,轉載請說明出處!

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

標籤:Java

上一篇:lombok.Getter cheated me

下一篇:返回列表

標籤雲
其他(159131) Python(38137) JavaScript(25431) Java(18047) C(15227) 區塊鏈(8267) C#(7972) AI(7469) 爪哇(7425) MySQL(7191) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5340) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4572) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2433) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1975) 功能(1967) Web開發(1951) HtmlCss(1937) python-3.x(1918) C++(1917) 弹簧靴(1913) xml(1889) PostgreSQL(1877) .NETCore(1861) 谷歌表格(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
最新发布
  • Spring原始碼:Bean生命周期(五)

    在今天的文章中,我們將深入探討 Bean 的屬性注入和初始化流程,從而使其成為一個真正意義上的 Bean。這個程序包括屬性注入、Aware 介面回呼、BeanPostProcessor 的前置和后置處理等多個步驟,通過本文的學習,讀者將能夠更深入地了解 Spring 框架中 Bean 的屬性注入和初... ......

    uj5u.com 2023-05-16 18:01:37 more
  • lombok.Getter cheated me

    下面這段代碼,IDE里正常顯示。不過,在build時,會報錯。 interface Doable { Integer getCode(); } @lombok.Getter class DerivedClass implements Doable { int code; } 錯誤資訊: Error: ......

    uj5u.com 2023-05-16 17:18:54 more
  • 限速神器RateLimiter原始碼決議

    作者:京東科技 李玉亮 目錄指引 限流場景 軟體系統中一般有兩種場景會用到限流: ?場景一、高并發的用戶端場景。 尤其是C端系統,經常面對海量用戶請求,如不做限流,遇到瞬間高并發的場景,則可能壓垮系統。 ?場景二、內部交易處理場景。 如某類交易任務處理時有速率要求,再如上下游呼叫時下游對上游有速率要 ......

    uj5u.com 2023-05-16 17:16:54 more
  • go多版本管理

    在日常開發作業程序中,很多時候我們都需要在自己的機器上安裝多個go版本,像是go1.16引入的embed,go1.18引入了泛型;又或是自己本地使用的是最新版,但公司的專案中使用的go1.14、go1.13甚至是更早的版本。 那么有沒有既不影響我們自己的本地環境,又能兼顧歷史專案的辦法呢?答案當然是 ......

    uj5u.com 2023-05-16 10:48:27 more
  • 技術宅拯救世界--你好,世界!

    public class Test{ public static void main(String[] args){ System.out.println("Hello,World!"); } } public 包外可呼叫的(此外還有protected、default、private) class ......

    uj5u.com 2023-05-16 10:43:21 more
  • 【C++】初始化串列建構式VS普通建構式

    普通建構式VS初始化串列建構式 初始化串列建構式最優先匹配問題 對于一個類而言,只要其中包含有初始化串列的建構式,編譯器在編譯使用{}語法的構造時會最傾向于呼叫初始化串列建構式,哪怕做型別轉換也在所不惜,哪怕有型別最佳匹配的普通建構式或移動建構式也會被劫持 class Widget { ......

    uj5u.com 2023-05-16 10:43:17 more
  • AccessToken、for_user、get_token

    在Django REST framework的SimpleJWT庫中,AccessToken是一個類,用于表示一個JSON Web Token (JWT)中的訪問令牌部分。訪問令牌是一種常見的身份驗證令牌,通常用于保護API端點。 通過SimpleJWT庫,您可以使用AccessToken類創建、解 ......

    uj5u.com 2023-05-16 10:43:12 more
  • Java并發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Java并發入門教程 - 從簡單的步驟了解Java并發,從基本到高級概念,包括概述,環境設定,主要操作,執行緒通信,同步,死鎖,ThreadLocal,ThreadLocalRandom,Lock,ReadWriteLock,Condition,AtomicInteger, AtomicLo ......

    uj5u.com 2023-05-16 10:41:13 more
  • TokenObtainPairSerialize和TokenObtainPairView

    TokenObtainPairSerializer和TokenObtainPairView是Django REST framework的SimpleJWT庫提供的兩個相關的類。 TokenObtainPairSerializer是一個用于序列化和驗證用戶憑證以生成JSON Web Token(JWT ......

    uj5u.com 2023-05-16 10:41:09 more
  • 訊息推送平臺有沒有保證資料不丟?

    我們在使用mq的時候,就會很自然思考一個問題:怎么保證資料不丟失? 現在austin接入層是把訊息發到mq,下發邏輯層從mq消費資料,隨后呼叫對應渠道介面來下發訊息。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.c ......

    uj5u.com 2023-05-16 10:41:05 more