主頁 > 後端開發 > Spring的后置處理器這么厲害?讓流程圖告訴你Spring啟動時的后置處理器作業流程

Spring的后置處理器這么厲害?讓流程圖告訴你Spring啟動時的后置處理器作業流程

2021-10-22 07:51:37 後端開發

探究Spring的后置處理器

文章目錄

      • 探究Spring的后置處理器
        • 流程圖
        • prepareRefresh剖析
        • obtainFreshBeanFactory刨析
        • prepareBeanFactory刨析
        • invokeBeanFactoryPostProcessors剖析

本次我們主要探究 invokeBeanFactoryPostProcessors();后面的代碼下次再做決議;

入口代碼refresh()

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// ......
applicationContext.refresh();
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 啟動前的準備作業:記錄啟動時間,活動標記為啟動以及環境屬性變數集合的初始化
			prepareRefresh();
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// Prepare the bean factory for use in this context.
			//還是一些準備作業,添加了兩個后置處理器:ApplicationContextAwareProcessor,ApplicationListenerDetector
			//還設定了 忽略自動裝配 和 允許自動裝配 的介面
			//對環境,系統環境,系統屬性三個Bean如果不存在某個bean的時候,spring就自動生成singleton bean(Not bd)
			//還設定了bean運算式決議器 等
			prepareBeanFactory(beanFactory);
			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 空方法
				postProcessBeanFactory(beanFactory);
				// Invoke factory processors registered as beans in the context.
				//執行自定義的BeanFactoryProcessor和內置的BeanFactoryProcessor
				invokeBeanFactoryPostProcessors(beanFactory);
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				// Initialize message source for this context.
				initMessageSource();
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();
				// Initialize other special beans in specific context subclasses.
				onRefresh();
				// Check for listener beans and register them.
				registerListeners();
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);
				// Last step: publish corresponding event.
				finishRefresh();
			}
			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

流程圖

在這里插入圖片描述

prepareRefresh剖析

該方法主要做啟動前的準備作業:記錄啟動時間,活動標記為啟動以及環境屬性變數集合的初始化;

	protected void prepareRefresh() {
		// Switch to active.
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);
		// Initialize any placeholder property sources in the context environment.
		// 空方法
		initPropertySources();
		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		getEnvironment().validateRequiredProperties();
		// Store pre-refresh ApplicationListeners...
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}
		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

obtainFreshBeanFactory刨析

主要是獲取context背景關系中的bean工廠;

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		// CAS保證同步
		refreshBeanFactory();
		// 回傳beanFactory- DefaultListableBeanFactory.class
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		return beanFactory;
	}

prepareBeanFactory刨析

做一些準備作業,添加了兩個后置處理器ApplicationContextAwareProcessorApplicationListenerDetector;

設定了bean運算式決議器等;

通過工廠的介面可以設定了忽略自動裝配,和允許自動裝配;

對環境、系統環境、系統屬性三個Bean如果不存在某個bean的時候,spring就自動生成singletonBean(Not bd);

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory)  {
    	// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		//設定bean運算式決議器
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		//屬性編輯器支持
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		//添加一個后置處理器:ApplicationContextAwareProcessor,此后置處理處理器實作了BeanPostProcessor介面
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		//以下介面,忽略自動裝配
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   		// .....
    	// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		//以下介面,允許自動裝配,第一個引數是自動裝配的型別,,第二個欄位是自動裝配的值
		// 這個介面僅會將注入的引數XXX.class注入為指定的值,但不影響XXX.class創建Bean物件;
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    	// Register default environment beans.
		// 環境,系統環境,系統屬性 因此通常情況下,這三個Bean是沒有bd的
		//如果沒有注冊過bean名稱為XXX,spring就自己創建一個名稱為XXX的singleton bean
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
}

invokeBeanFactoryPostProcessors剖析

執行自定義的BeanFactoryProcessor和內置的BeanFactoryProcessor;

getBeanFactoryPostProcessors()方法是我們手動通過執行addBeanFactoryPostProcessor(XX)設定自定義的后置處理器,如果初始化執行到這,沒有手動增加后置處理器的話,那么此時List<BeanFactoryPostProcessor>的size()為empty;

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	// getBeanFactoryPostProcessors是spring允許我們手動添加BeanFactoryPostProcessor
	// 即:annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX);
    // 未手動添加的話,getBeanFactoryPostProcessors()為empty
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

我們通過委托PostProcessorRegistrationDelegate去呼叫invokeBeanFactoryPostProcessors()方法,從而去掃描并執行BeanFactoryProcessorBeanDefinitionRegistryPostProcessor;

我們通過繼承關系看,BeanDefinitionRegistryPostProcessor實際上是繼承BeanFactoryProcessor介面的;

在這里插入圖片描述

  • BeanDefinitionRegistryPostProcessor:主要掃描類決議類;
  • BeanFactoryProcessor:主要給配置類進行增強代理;

這里面需要看我們的BeanFactory的型別;初始時BeanFactory的型別是DefaultListableBeanFactory;因此,該bean工廠是實作BeanDefinitionRegistry;

在這里插入圖片描述

該方法的具體流程如下(按初始化進入到這里描述):

  1. 回圈遍歷手動添加的后置處理器(并不排序);

  2. 若該bfp是bdrp則直接執行bdrp. postProcessBeanDefinitionRegistry();

  3. 取出內置的bdrp,分為實作了PriorityOrdered,Ordered和都沒有實作的三類;

    初始這里只有一個,就是我們在初始化reader()時,注冊了一個ConfigurationClassPostProcessor.class;

    在這里插入圖片描述

    public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
    		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {}
    
  4. 將上面三類直接執行bdrp. postProcessBeanDefinitionRegistry();

  5. 然后將手動加入和內置的bdrp執行bfp.postProcessBeanFactory();

  6. 上面的已經執行完了:

    • 手動添加的后置處理器的bdrf. postProcessBeanDefinitionRegistry()bfp.postProcessBeanFactory();
    • 內置的bdrp. postProcessBeanDefinitionRegistry()
  7. 取出內置的bfp,分為實作了PriorityOrdered, Ordered和都沒有實作的三類;

    目前這里內置的有兩個,但其中config上面已經執行過了,此處只執行下方的一個;

    在這里插入圖片描述

  8. 將上面三類直接執行bfp. postProcessBeanDefinitionRegistry();

  9. 清除快取中的bd,因為后處理器可能有修改了原始元資料,例如替換值中的占位符;

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		// 如果不是BeanDefinitionRegistry 則直接執行beanFactoryPostProcessors
		// 剛啟動時傳入的beanFactory是DefaultListableBeanFactory,他是實作了BeanDefinitionRegistry 因此會走這里
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			// bf后置處理器集合(手動添加與bdr后置處理器集合【下面的那個集合】):因為bdrp屬于bfp
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			// bdr后置處理器集合(手動添加與spring自己的)
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			// 回圈傳進來的beanFactoryPostProcessors,剛啟動時未手動增加的情況下beanFactoryPostProcessors肯定沒有資料
			// 因為beanFactoryPostProcessors是獲得手動添加的,而不是spring掃描的
			// 只有手動呼叫annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX)才會有資料
			// 執行手動添加的beanFactoryPostProcessors, 如果是BeanDefinitionRegistryPostProcessor,則執行其postProcessBeanDefinitionRegistry再加到list中
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}
			//一個臨時變數,用來裝載BeanDefinitionRegistryPostProcessor為了排序
			//BeanDefinitionRegistry繼承了PostProcessorBeanFactoryPostProcessor
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// 獲得實作BeanDefinitionRegistryPostProcessor介面的類
			// 就是ConfigurationClassPostProcessor(Spring自己添加的-在reader()時增加的)
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					//獲得ConfigurationClassPostProcessor類,并且放到currentRegistryProcessors
					//ConfigurationClassPostProcessor是很重要的一個類,它實作了BeanDefinitionRegistryPostProcessor介面
					//BeanDefinitionRegistryPostProcessor介面又實作了BeanFactoryPostProcessor介面
					//ConfigurationClassPostProcessor是極其重要的類
					//里面執行了掃描Bean,Import,ImportResouce等各種操作
					//用來處理配置類(有兩種情況 一種是傳統意義上的配置類,一種是普通的bean)的各種邏輯
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					//把name放到processedBeans,后續會根據這個集合來判斷處理器是否已經被執行過了
					processedBeans.add(ppName);
				}
			}
			//處理排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			//合并Processors,為什么要合并,因為registryProcessors是裝載BeanDefinitionRegistryPostProcessor的
			//一開始的時候,spring只會執行BeanDefinitionRegistryPostProcessor獨有的方法
			//而不會執行BeanDefinitionRegistryPostProcessor父類的方法,即BeanFactoryProcessor的方法
			//所以這里需要把處理器放入一個集合中,后續統一執行父類的方法
			registryProcessors.addAll(currentRegistryProcessors);
			//可以理解為執行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
			//Spring熱插播的體現,像ConfigurationClassPostProcessor就相當于一個組件,Spring很多事情就是交給組件去管理
			//將spring提供的RegistryProcessors(就是這個ConfigurationClassPostProcessor)執行其postProcessBeanDefinitionRegistry
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			//清空臨時變數
			currentRegistryProcessors.clear();
			// 再次根據BeanDefinitionRegistryPostProcessor獲得BeanName,看這個BeanName是否已經被執行過了,有沒有實作Ordered介面
			// 如果沒有被執行過,也實作了Ordered介面的話,把物件推送到currentRegistryProcessors,名稱推送到processedBeans
			// 如果沒有實作Ordered介面的話,這里不把資料加到currentRegistryProcessors,processedBeans中,后續再做處理
			// 這里才可以獲得我們定義的實作了BeanDefinitionRegistryPostProcessor的Bean
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			//處理排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			//合并Processors
			registryProcessors.addAll(currentRegistryProcessors);
			//執行有Ordered的BeanDefinitionRegistryPostProcessor
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			//清空臨時變數
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			// 下面的代碼就是執行沒有實作PriorityOrdered介面也沒有Ordered的BeanDefinitionRegistryPostProcessor
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			//registryProcessors集合裝載BeanDefinitionRegistryPostProcessor
			//上面的代碼是執行bfr后置處理器子類獨有的方法,這里需要再把bfr后置處理器父類的方法也執行一次
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			//regularPostProcessors裝載BeanFactoryPostProcessor,執行BeanFactoryPostProcessor的方法
			//但是regularPostProcessors一般情況下,是不會有資料的,只有在外面手動添加BeanFactoryPostProcessor,才會有資料
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			// 若bfp沒有繼承bdrp則直接執行手動增加bf后置處理器的后置處理器
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		// 找到BeanFactoryPostProcessor實作類的BeanName陣列
		// 處理Spring自己的bf后置處理器
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		// PriorityOrdered的bf后置處理器集合
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		// Ordered的bf后置處理器集合
		List<String> orderedPostProcessorNames = new ArrayList<>();
		// 無PriorityOrdered無Ordered的bf后置處理器集合
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		//回圈BeanName陣列
		for (String ppName : postProcessorNames) {
			//如果這個Bean被執行過了,跳過
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			//如果實作了PriorityOrdered介面,加入到priorityOrderedPostProcessors
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			//如果實作了Ordered介面,加入到orderedPostProcessorNames
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			//如果既沒有實作PriorityOrdered,也沒有實作Ordered,加入到nonOrderedPostProcessorNames
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		//排序處理priorityOrderedPostProcessors,即實作了PriorityOrdered介面的BeanFactoryPostProcessor
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		//執行priorityOrderedPostProcessors
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		//執行實作了Ordered介面的BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		// 執行既沒有實作PriorityOrdered介面,也沒有實作Ordered介面的BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		// 清除了allBeanNamesByType&singletonBeanNamesByType()
		// 清除快取中的bd,因為后處理器可能有修改了原始元資料,例如替換值中的占位符
		beanFactory.clearMetadataCache();
	}

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

標籤:java

上一篇:java集合中的Map集合

下一篇:使用IDEA搭建一個簡單的SpringBoot專案——————超級詳細(包含一些報錯)本人親測無誤

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(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
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more