主頁 > 後端開發 > Spring容器的啟動流程

Spring容器的啟動流程

2021-02-20 11:13:53 後端開發

(本文基于 Spring 的 5.1.6.RELEASE 版本)

Spring的啟動流程可以歸納為三個步驟:

  • 1、初始化Spring容器,注冊內置的BeanPostProcessor的BeanDefinition到容器中
  • 2、將配置類的BeanDefinition注冊到容器中
  • 3、呼叫refresh()方法重繪容器

因為是基于 java-config 技術分析原始碼,所以這里的入口是 AnnotationConfigApplicationContext ,如果是使用 xml 分析,那么入口即為 ClassPathXmlApplicationContext ,它們倆的共同特征便是都繼承了 AbstractApplicationContext 類,而大名鼎鼎的 refresh()便是在這個類中定義的,我們接著分析 AnnotationConfigApplicationContext 類,原始碼如下:

// 初始化容器
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    // 注冊 Spring 內置后置處理器的 BeanDefinition 到容器
    this();
    // 注冊配置類 BeanDefinition 到容器
    register(annotatedClasses);
    // 加載或者重繪容器中的Bean
    refresh();
}

所以整個Spring容器的啟動流程可以繪制成如下流程圖:

接著我們主要從這三個入口詳細分析一下Spring的啟動流程:

一、初始化流程:

1、spring容器的初始化時,通過this()呼叫了無參建構式,主要做了以下三個事情:

  • (1)實體化BeanFactory【DefaultListableBeanFactory】工廠,用于生成Bean物件
  • (2)實體化BeanDefinitionReader注解配置讀取器,用于對特定注解(如@Service、@Repository)的類進行讀取轉化成 BeanDefinition 物件,(BeanDefinition 是 Spring 中極其重要的一個概念,它存盤了 bean 物件的所有特征資訊,如是否單例,是否懶加載,factoryBeanName 等)
  • (3)實體化ClassPathBeanDefinitionScanner路徑掃描器,用于對指定的包目錄進行掃描查找 bean 物件

2、核心代碼剖析:

(1)向容器添加內置組件:org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors:

根據上圖分析,代碼運行到這里時候,Spring 容器已經構造完畢,那么就可以為容器添加一些內置組件了,其中最主要的組件便是 ConfigurationClassPostProcessor 和 AutowiredAnnotationBeanPostProcessor ,前者是一個 beanFactory 后置處理器,用來完成 bean 的掃描與注入作業,后者是一個 bean 后置處理器,用來完成 @AutoWired 自動注入,

二、注冊SpringConfig配置類到容器中:

1、將SpringConfig注冊到容器中:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean:

這個步驟主要是用來決議用戶傳入的 Spring 配置類,決議成一個 BeanDefinition 然后注冊到容器中,主要原始碼如下:

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
		@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
	// 決議傳入的配置類,實際上這個方法既可以決議配置類,也可以決議 Spring bean 物件
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
	// 判斷是否需要跳過,判斷依據是此類上有沒有 @Conditional 注解
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

	abd.setInstanceSupplier(instanceSupplier);
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
	// 處理類上的通用注解
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			}
			else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			}
			else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}
	// 封裝成一個 BeanDefinitionHolder
	for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
		customizer.customize(abd);
	}
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	// 處理 scopedProxyMode
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

	// 把 BeanDefinitionHolder 注冊到 registry
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

三、refresh()容器重繪流程:

refresh()主要用于容器的重繪,Spring 中的每一個容器都會呼叫 refresh() 方法進行重繪,無論是 Spring 的父子容器,還是 Spring Cloud Feign 中的 feign 隔離容器,每一個容器都會呼叫這個方法完成初始化,refresh()可劃分為12個步驟,其中比較重要的步驟下面會有詳細說明,

1、refresh()方法的原始碼:org.springframework.context.support.AbstractApplicationContext#refresh:

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 1. 重繪前的預處理
		prepareRefresh();

		// 2. 獲取 beanFactory,即前面創建的【DefaultListableBeanFactory】
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 3. 預處理 beanFactory,向容器中添加一些組件
		prepareBeanFactory(beanFactory);

		try {
			// 4. 子類通過重寫這個方法可以在 BeanFactory 創建并與準備完成以后做進一步的設定
			postProcessBeanFactory(beanFactory);

			// 5. 執行 BeanFactoryPostProcessor 方法,beanFactory 后置處理器
			invokeBeanFactoryPostProcessors(beanFactory);

			// 6. 注冊 BeanPostProcessors,bean 后置處理器
			registerBeanPostProcessors(beanFactory);

			// 7. 初始化 MessageSource 組件(做國際化功能;訊息系結,訊息決議)
			initMessageSource();

			// 8. 初始化事件派發器,在注冊監聽器時會用到
			initApplicationEventMulticaster();

			// 9. 留給子容器(子類),子類重寫這個方法,在容器重繪的時候可以自定義邏輯,web 場景下會使用
			onRefresh();

			// 10. 注冊監聽器,派發之前步驟產生的一些事件(可能沒有)
			registerListeners();

			// 11. 初始化所有的非單實體 bean
			finishBeanFactoryInitialization(beanFactory);

			// 12. 發布容器重繪完成事件
			finishRefresh();
		}
		...
	}
}

首先我們總結一下refresh()方法每一步主要的功能:之后再對每一步的原始碼做具體的分析

1、prepareRefresh()重繪前的預處理:

  • (1)initPropertySources():初始化一些屬性設定,子類自定義個性化的屬性設定方法;
  • (2)getEnvironment().validateRequiredProperties():檢驗屬性的合法性
  • (3)earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>():保存容器中的一些早期的事件;

2、obtainFreshBeanFactory():獲取在容器初始化時創建的BeanFactory:

  • (1)refreshBeanFactory():重繪BeanFactory,設定序列化ID;
  • (2)getBeanFactory():回傳初始化中的GenericApplicationContext創建的BeanFactory物件,即【DefaultListableBeanFactory】型別

3、prepareBeanFactory(beanFactory):BeanFactory的預處理作業,向容器中添加一些組件:

  • (1)設定BeanFactory的類加載器、設定運算式決議器等等
  • (2)添加BeanPostProcessor【ApplicationContextAwareProcessor】
  • (3)設定忽略自動裝配的介面:EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware;
  • (4)注冊可以決議的自動裝配類,即可以在任意組件中通過注解自動注入:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
  • (5)添加BeanPostProcessor【ApplicationListenerDetector】
  • (6)添加編譯時的AspectJ;
  • (7)給BeanFactory中注冊的3個組件:environment【ConfigurableEnvironment】、systemProperties【Map<String, Object>】、systemEnvironment【Map<String, Object>】

4、postProcessBeanFactory(beanFactory):子類重寫該方法,可以實作在BeanFactory創建并預處理完成以后做進一步的設定

5、invokeBeanFactoryPostProcessors(beanFactory):在BeanFactory標準初始化之后執行BeanFactoryPostProcessor的方法,即BeanFactory的后置處理器:

(1)先執行BeanDefinitionRegistryPostProcessor: postProcessor.postProcessBeanDefinitionRegistry(registry)

  • ① 獲取所有的實作了BeanDefinitionRegistryPostProcessor介面型別的集合
  • ② 先執行實作了PriorityOrdered優先級介面的BeanDefinitionRegistryPostProcessor
  • ③ 再執行實作了Ordered順序介面的BeanDefinitionRegistryPostProcessor
  • ④ 最后執行沒有實作任何優先級或者是順序介面的BeanDefinitionRegistryPostProcessors

(2)再執行BeanFactoryPostProcessor的方法:postProcessor.postProcessBeanFactory(beanFactory)

  • ① 獲取所有的實作了BeanFactoryPostProcessor介面型別的集合
  • ② 先執行實作了PriorityOrdered優先級介面的BeanFactoryPostProcessor
  • ③ 再執行實作了Ordered順序介面的BeanFactoryPostProcessor
  • ④ 最后執行沒有實作任何優先級或者是順序介面的BeanFactoryPostProcessor

6、registerBeanPostProcessors(beanFactory):向容器中注冊Bean的后置處理器BeanPostProcessor,它的主要作用是干預Spring初始化bean的流程,從而完成代理、自動注入、回圈依賴等功能

  • (1)獲取所有實作了BeanPostProcessor介面型別的集合:
  • (2)先注冊實作了PriorityOrdered優先級介面的BeanPostProcessor;
  • (3)再注冊實作了Ordered優先級介面的BeanPostProcessor;
  • (4)最后注冊沒有實作任何優先級介面的BeanPostProcessor;
  • (5)最refresh主要可劃分為12個步驟,其中比較重要的步驟下面會有詳細說明,Spring 中的每一個容器都會呼叫 refresh() 方法進行重繪,無論是 Spring 的父子容器,還是 Spring Cloud Feign 中的 feign 隔離容器,每一個容器都會呼叫這個方法完成初始化,終注冊MergedBeanDefinitionPostProcessor型別的BeanPostProcessor:beanFactory.addBeanPostProcessor(postProcessor);
  • (6)給容器注冊一個ApplicationListenerDetector:用于在Bean創建完成后檢查是否是ApplicationListener,如果是,就把Bean放到容器中保存起來:applicationContext.addApplicationListener((ApplicationListener<?>) bean);

此時容器中默認有6個默認的BeanProcessor(無任何代理模式下):【ApplicationContextAwareProcessor】、【ConfigurationClassPostProcessorsAwareBeanPostProcessor】、【PostProcessorRegistrationDelegate】、【CommonAnnotationBeanPostProcessor】、【AutowiredAnnotationBeanPostProcessor】、【ApplicationListenerDetector】

7、initMessageSource():初始化MessageSource組件,主要用于做國際化功能,訊息系結與訊息決議:

  • (1)看BeanFactory容器中是否有id為messageSource 并且型別是MessageSource的組件:如果有,直接賦值給messageSource;如果沒有,則創建一個DelegatingMessageSource;
  • (2)把創建好的MessageSource注冊在容器中,以后獲取國際化組態檔的值的時候,可以自動注入MessageSource;

8、initApplicationEventMulticaster():初始化事件派發器,在注冊監聽器時會用到:

  • (1)看BeanFactory容器中是否存在自定義的ApplicationEventMulticaster:如果有,直接從容器中獲取;如果沒有,則創建一個SimpleApplicationEventMulticaster
  • (2)將創建的ApplicationEventMulticaster添加到BeanFactory中,以后其他組件就可以直接自動注入

9、onRefresh():留給子容器、子類重寫這個方法,在容器重繪的時候可以自定義邏輯

10、registerListeners():注冊監聽器:將容器中所有的ApplicationListener注冊到事件派發器中,并派發之前步驟產生的事件:

  • (1)從容器中拿到所有的ApplicationListener
  • (2)將每個監聽器添加到事件派發器中:getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  • (3)派發之前步驟產生的事件applicationEvents:getApplicationEventMulticaster().multicastEvent(earlyEvent);

11、finishBeanFactoryInitialization(beanFactory):初始化所有剩下的單實體bean,核心方法是preInstantiateSingletons(),會呼叫getBean()方法創建物件;

  • (1)獲取容器中的所有beanDefinitionName,依次進行初始化和創建物件
  • (2)獲取Bean的定義資訊RootBeanDefinition,它表示自己的BeanDefinition和可能存在父類的BeanDefinition合并后的物件
  • (3)如果Bean滿足這三個條件:非抽象的,單實體,非懶加載,則執行單例Bean創建流程:
  • (4)所有Bean都利用getBean()創建完成以后,檢查所有的Bean是否為SmartInitializingSingleton介面的,如果是;就執行afterSingletonsInstantiated();

12、finishRefresh():發布BeanFactory容器重繪完成事件:

  • (1)initLifecycleProcessor():初始化和生命周期有關的后置處理器:默認從容器中找是否有lifecycleProcessor的組件【LifecycleProcessor】,如果沒有,則創建一個DefaultLifecycleProcessor()加入到容器;
  • (2)getLifecycleProcessor().onRefresh():拿到前面定義的生命周期處理器(LifecycleProcessor)回呼onRefresh()方法
  • (3)publishEvent(new ContextRefreshedEvent(this)):發布容器重繪完成事件;
  • (4)liveBeansView.registerApplicationContext(this);

2、第三步:BeanFactory的預處理:org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory:

這一步主要為 beanFactory 工廠添加一些內置組件

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 設定 classLoader
	beanFactory.setBeanClassLoader(getClassLoader());
	//設定 bean 運算式決議器
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// 添加一個 BeanPostProcessor【ApplicationContextAwareProcessor】
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

	// 設定忽略自動裝配的介面,即不能通過注解自動注入
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// 注冊可以決議的自動裝配類,即可以在任意組件中通過注解自動注入
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// 添加一個 BeanPostProcessor【ApplicationListenerDetector】
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// 添加編譯時的 AspectJ
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// 注冊 environment 組件,型別是【ConfigurableEnvironment】
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	// 注冊 systemProperties 組件,型別是【Map<String, Object>】
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	// 注冊 systemEnvironment 組件,型別是【Map<String, Object>】
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
}

執行流程小結:

  • (1)設定BeanFactory的類加載器、設定運算式決議器等等
  • (2)添加BeanPostProcessor【ApplicationContextAwareProcessor】
  • (3)設定忽略自動裝配的介面:EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware;
  • (4)注冊可以決議的自動裝配類,即可以在任意組件中通過注解自動注入:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
  • (5)添加BeanPostProcessor【ApplicationListenerDetector】
  • (6)添加編譯時的AspectJ;
  • (7)給BeanFactory中注冊的3個組件:environment【ConfigurableEnvironment】、systemProperties【Map<String, Object>】、systemEnvironment【Map<String, Object>】

3、第五步:執行BeanFactory的后置處理器:org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors:

Spring 在掃描完所有的 bean 轉成 BeanDefinition 時候,允許我們做一些自定義操作,這得益于 Spring 為我們提供的 BeanFactoryPostProcessor 介面,

其中 BeanFactoryPostProcessor 又有一個子介面 BeanDefinitionRegistryPostProcessor ,前者會把 ConfigurableListableBeanFactory 暴露給我們使用,后者會把 BeanDefinitionRegistry 注冊器暴露給我們使用,一旦獲取到注冊器,我們就可以按需注入了,

同時 Spring 是允許我們控制同型別組件的順序,比如在 AOP 中我們常用的 @Order 注解,這里的 BeanFactoryPostProcessor 介面當然也是提供了順序,最先被執行的是實作了 PriorityOrdered 介面的實作類,然后再到實作了 Ordered 介面的實作類,最后就是剩下來的常規 BeanFactoryPostProcessor 類,

此時再看上圖,是不是發現和喝水一般簡單,首先會回呼 postProcessBeanDefinitionRegistry() 方法,然后再回呼 postProcessBeanFactory() 方法,最后注意順序即可,下面一起看看具體的代碼實作吧,

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
	// beanFactoryPostProcessors 這個引數是指用戶通過 AnnotationConfigApplicationContext.addBeanFactoryPostProcessor() 方法手動傳入的 BeanFactoryPostProcessor,沒有交給 spring 管理
	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
	// 代表執行過的 BeanDefinitionRegistryPostProcessor
	Set<String> processedBeans = new HashSet<>();

	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		// 常規后置處理器集合,即實作了 BeanFactoryPostProcessor 介面
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		// 注冊后置處理器集合,即實作了 BeanDefinitionRegistryPostProcessor 介面
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
		// 處理自定義的 beanFactoryPostProcessors(指呼叫 context.addBeanFactoryPostProcessor() 方法),一般這里都沒有
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				// 呼叫 postProcessBeanDefinitionRegistry 方法
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		// Separate between BeanDefinitionRegistryPostProcessors that implement
		// PriorityOrdered, Ordered, and the rest.
		// 定義一個變數 currentRegistryProcessors,表示當前要處理的 BeanFactoryPostProcessors
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
		// 首先,從容器中查找實作了 PriorityOrdered 介面的 BeanDefinitionRegistryPostProcessor 型別,這里只會查找出一個【ConfigurationClassPostProcessor】
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			// 判斷是否實作了 PriorityOrdered 介面
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				// 添加到 currentRegistryProcessors
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				// 添加到 processedBeans,表示已經處理過這個類了
				processedBeans.add(ppName);
			}
		}
		// 設定排列順序
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		// 添加到 registry 中
		registryProcessors.addAll(currentRegistryProcessors);
		// 執行 [postProcessBeanDefinitionRegistry] 回呼方法
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		// 將 currentRegistryProcessors 變數清空,下面會繼續用到
		currentRegistryProcessors.clear();

		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
		// 接下來,從容器中查找實作了 Ordered 介面的 BeanDefinitionRegistryPostProcessors 型別,這里可能會查找出多個
		// 因為【ConfigurationClassPostProcessor】已經完成了 postProcessBeanDefinitionRegistry() 方法,已經向容器中完成掃描作業,所以容器會有很多個組件
		postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			// 判斷 processedBeans 是否處理過這個類,且是否實作 Ordered 介面
			if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		// 設定排列順序
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		// 添加到 registry 中
		registryProcessors.addAll(currentRegistryProcessors);
		// 執行 [postProcessBeanDefinitionRegistry] 回呼方法
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		// 將 currentRegistryProcessors 變數清空,下面會繼續用到
		currentRegistryProcessors.clear();

		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
		// 最后,從容器中查找剩余所有常規的 BeanDefinitionRegistryPostProcessors 型別
		boolean reiterate = true;
		while (reiterate) {
			reiterate = false;
			// 根據型別從容器中查找
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				// 判斷 processedBeans 是否處理過這個類
				if (!processedBeans.contains(ppName)) {
					// 添加到 currentRegistryProcessors
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					// 添加到 processedBeans,表示已經處理過這個類了
					processedBeans.add(ppName);
					// 將標識設定為 true,繼續回圈查找,可能隨時因為防止下面呼叫了 invokeBeanDefinitionRegistryPostProcessors() 方法引入新的后置處理器
					reiterate = true;
				}
			}
			// 設定排列順序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			// 添加到 registry 中
			registryProcessors.addAll(currentRegistryProcessors);
			// 執行 [postProcessBeanDefinitionRegistry] 回呼方法
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			// 將 currentRegistryProcessors 變數清空,因為下一次回圈可能會用到
			currentRegistryProcessors.clear();
		}

		// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
		// 現在執行 registryProcessors 的 [postProcessBeanFactory] 回呼方法
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		// 執行 regularPostProcessors 的 [postProcessBeanFactory] 回呼方法,也包含用戶手動呼叫 addBeanFactoryPostProcessor() 方法添加的 BeanFactoryPostProcessor
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}

	else {
		// Invoke factory processors registered with the context instance.
		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 介面的類
	String[] postProcessorNames =
			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

	// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	// 表示實作了 PriorityOrdered 介面的 BeanFactoryPostProcessor
	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	// 表示實作了 Ordered 介面的 BeanFactoryPostProcessor
	List<String> orderedPostProcessorNames = new ArrayList<>();
	// 表示剩下來的常規的 BeanFactoryPostProcessors
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		// 判斷是否已經處理過,因為 postProcessorNames 其實包含了上面步驟處理過的 BeanDefinitionRegistry 型別
		if (processedBeans.contains(ppName)) {
			// skip - already processed in first phase above
		}
		// 判斷是否實作了 PriorityOrdered 介面
		else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
		}
		// 判斷是否實作了 Ordered 介面
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		// 剩下所有常規的
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
	// 先將 priorityOrderedPostProcessors 集合排序
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	// 執行 priorityOrderedPostProcessors 的 [postProcessBeanFactory] 回呼方法
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
	// 接下來,把 orderedPostProcessorNames 轉成 orderedPostProcessors 集合
	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
	for (String postProcessorName : orderedPostProcessorNames) {
		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	// 將 orderedPostProcessors 集合排序
	sortPostProcessors(orderedPostProcessors, beanFactory);
	// 執行 orderedPostProcessors 的 [postProcessBeanFactory] 回呼方法
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

	// Finally, invoke all other BeanFactoryPostProcessors.
	// 最后把 nonOrderedPostProcessorNames 轉成 nonOrderedPostProcessors 集合,這里只有一個,myBeanFactoryPostProcessor
	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	for (String postProcessorName : nonOrderedPostProcessorNames) {
		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	// 執行 nonOrderedPostProcessors 的 [postProcessBeanFactory] 回呼方法
	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

	// Clear cached merged bean definitions since the post-processors might have
	// modified the original metadata, e.g. replacing placeholders in values...
	// 清除快取
	beanFactory.clearMetadataCache();
}

執行流程小結:

(1)先執行BeanDefinitionRegistryPostProcessor: postProcessor.postProcessBeanDefinitionRegistry(registry)

  • ① 獲取所有的實作了BeanDefinitionRegistryPostProcessor介面型別的集合
  • ② 先執行實作了PriorityOrdered優先級介面的BeanDefinitionRegistryPostProcessor
  • ③ 再執行實作了Ordered順序介面的BeanDefinitionRegistryPostProcessor
  • ④ 最后執行沒有實作任何優先級或者是順序介面的BeanDefinitionRegistryPostProcessors

(2)再執行BeanFactoryPostProcessor的方法:postProcessor.postProcessBeanFactory(beanFactory)

  • ① 獲取所有的實作了BeanFactoryPostProcessor介面型別的集合
  • ② 先執行實作了PriorityOrdered優先級介面的BeanFactoryPostProcessor
  • ③ 再執行實作了Ordered順序介面的BeanFactoryPostProcessor
  • ④ 最后執行沒有實作任何優先級或者是順序介面的BeanFactoryPostProcessor

4、第六步:注冊Bean的后置處理器:org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors:

這一步是向容器中注入 BeanPostProcessor 后置處理器,注意這里僅僅是向容器中注入而非使用,關于 BeanPostProcessor ,它的作用主要是會干預 Spring 初始化 bean 的流程,從而完成代理、自動注入、回圈依賴等各種功能,

public static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

	// 從容器中獲取 BeanPostProcessor 型別
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

	// Register BeanPostProcessorChecker that logs an info message when
	// a bean is created during BeanPostProcessor instantiation, i.e. when
	// a bean is not eligible for getting processed by all BeanPostProcessors.
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	// 向容器中添加【BeanPostProcessorChecker】,主要是用來檢查是不是有 bean 已經初始化完成了,
	// 如果沒有執行所有的 beanPostProcessor(用數量來判斷),如果有就會列印一行 info 日志
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

	// Separate between BeanPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	// 存放實作了 PriorityOrdered 介面的 BeanPostProcessor
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	// 存放 MergedBeanDefinitionPostProcessor 型別的 BeanPostProcessor
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	// 存放實作了 Ordered 介面的 BeanPostProcessor 的 name
	List<String> orderedPostProcessorNames = new ArrayList<>();
	// 存放剩下來普通的 BeanPostProcessor 的 name
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	// 從 beanFactory 中查找 postProcessorNames 里的 bean,然后放到對應的集合中
	for (String ppName : postProcessorNames) {
		// 判斷有無實作 PriorityOrdered 介面
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			// 如果實作了 PriorityOrdered 介面,且屬于 MergedBeanDefinitionPostProcessor
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				// 把 MergedBeanDefinitionPostProcessor 型別的添加到 internalPostProcessors 集合中
				internalPostProcessors.add(pp);
			}
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// First, register the BeanPostProcessors that implement PriorityOrdered.
	// 給 priorityOrderedPostProcessors 排序
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	// 先注冊實作了 PriorityOrdered 介面的 beanPostProcessor
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

	// Next, register the BeanPostProcessors that implement Ordered.
	// 從 beanFactory 中查找 orderedPostProcessorNames 里的 bean,然后放到對應的集合中
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	// 給 orderedPostProcessors 排序
	sortPostProcessors(orderedPostProcessors, beanFactory);
	// 再注冊實作了 Ordered 介面的 beanPostProcessor
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

	// Now, register all regular BeanPostProcessors.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	// 再注冊常規的 beanPostProcessor
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

	// Finally, re-register all internal BeanPostProcessors.
	// 排序 MergedBeanDefinitionPostProcessor 這種型別的 beanPostProcessor
	sortPostProcessors(internalPostProcessors, beanFactory);
	// 最后注冊 MergedBeanDefinitionPostProcessor 型別的 beanPostProcessor
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// Re-register post-processor for detecting inner beans as ApplicationListeners,
	// moving it to the end of the processor chain (for picking up proxies etc).
	// 給容器中添加【ApplicationListenerDetector】 beanPostProcessor,判斷是不是監聽器,如果是就把 bean 放到容器中保存起來
	// 此時容器中默認會有 6 個內置的 beanPostProcessor
		// 0 = {ApplicationContextAwareProcessor@1632}
		//	1 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@1633}
		//	2 = {PostProcessorRegistrationDelegate$BeanPostProcessorChecker@1634}
		//	3 = {CommonAnnotationBeanPostProcessor@1635}
		//	4 = {AutowiredAnnotationBeanPostProcessor@1636}
		//	5 = {ApplicationListenerDetector@1637}
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

執行流程小結:

  • (1)獲取所有實作了BeanPostProcessor介面型別的集合:
  • (2)先注冊實作了PriorityOrdered優先級介面的BeanPostProcessor;
  • (3)再注冊實作了Ordered優先級介面的BeanPostProcessor;
  • (4)最后注冊沒有實作任何優先級介面的BeanPostProcessor;
  • (5)最終注冊MergedBeanDefinitionPostProcessor型別的BeanPostProcessor;
  • (6)給容器注冊一個ApplicationListenerDetector:用于在Bean創建完成后檢查是否是ApplicationListener,如果是,就把Bean放到容器中保存起來:applicationContext.addApplicationListener((ApplicationListener<?>) bean);

5、第八步:初始化事件派發器:org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster:

前文我們說到,在整個容器創建程序中,Spring 會發布很多容器事件,如容器啟動、重繪、關閉等,這個功能的實作得益于這里的 ApplicationEventMulticaster 廣播器組件,通過它來派發事件通知,

protected void initApplicationEventMulticaster() {
	// 獲取 beanFactory
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	// 看看容器中是否有自定義的 applicationEventMulticaster
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		// 有就從容器中獲取賦值
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
		}
	}
	else {
		// 沒有,就創建一個 SimpleApplicationEventMulticaster
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		// 將創建的 ApplicationEventMulticaster 添加到 BeanFactory 中, 其他組件就可以自動注入了
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		if (logger.isTraceEnabled()) {
			logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
					"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
		}
	}
}

執行流程小結:

  • (1)看BeanFactory容器中是否存在自定義的ApplicationEventMulticaster:如果有,直接從容器中獲取;如果沒有,則創建一個SimpleApplicationEventMulticaster
  • (2)將創建的ApplicationEventMulticaster添加到BeanFactory中,以后其他組件就可以直接自動注入

6、第十步:注冊ApplicationListener監聽器:org.springframework.context.support.AbstractApplicationContext#registerListeners:

這一步主要是將容器中所有的ApplicationListener注冊到事件派發器中,并派發之前步驟產生的事件,

protected void registerListeners() {
	// Register statically specified listeners first.
	// 獲取之前步驟中保存的 ApplicationListener
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		// getApplicationEventMulticaster() 就是獲取之前步驟初始化的 applicationEventMulticaster
		getApplicationEventMulticaster().addApplicationListener(listener);
	}

	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	// 從容器中獲取所有的 ApplicationListener
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String listenerBeanName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}

	// Publish early application events now that we finally have a multicaster...
	// 派發之前步驟產生的 application events
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (earlyEventsToProcess != null) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}

執行流程小結:

  • (1)從容器中拿到所有的ApplicationListener
  • (2)將每個監聽器添加到事件派發器中:getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  • (3)派發之前步驟產生的事件applicationEvents:getApplicationEventMulticaster().multicastEvent(earlyEvent);

7、第十一步:初始化所有的單例Bean:org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons:

在前面的步驟中,Spring 的大多陣列件都已經初始化完畢了,剩下來的這個步驟就是初始化所有剩余的單實體 bean,Spring主要是通過preInstantiateSingletons()方法把容器中的 bean 都初始化完畢,這里我們就不細講Bean的創建流程了,

public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	// 獲取容器中的所有 beanDefinitionName
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	// 回圈進行初始化和創建物件
	for (String beanName : beanNames) {
		// 獲取 RootBeanDefinition,它表示自己的 BeanDefinition 和可能存在父類的 BeanDefinition 合并后的物件
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 如果是非抽象的,且單實體,非懶加載
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 如果是 factoryBean,利用下面這種方法創建物件
			if (isFactoryBean(beanName)) {
				// 如果是 factoryBean,則 加上 &,先創建工廠 bean
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				// 不是工廠 bean,用這種方法創建物件
				getBean(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		// 檢查所有的 bean 是否是 SmartInitializingSingleton 介面
		if (singletonInstance instanceof SmartInitializingSingleton) {
			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				// 回呼 afterSingletonsInstantiated() 方法,可以在回呼中做一些事情
				smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

執行流程小結:

  • (1)獲取容器中的所有beanDefinitionName,依次進行初始化和創建物件
  • (2)獲取Bean的定義資訊RootBeanDefinition,它表示自己的BeanDefinition和可能存在父類的BeanDefinition合并后的物件
  • (3)如果Bean滿足這三個條件:非抽象的,單實體,非懶加載,則執行單例Bean創建流程:
  • (4)所有Bean都利用getBean()創建完成以后,檢查所有的Bean是否為SmartInitializingSingleton介面的,如果是;就執行afterSingletonsInstantiated();

8、第十二步:發布BeanFactory容器重繪完成事件:org.springframework.context.support.AbstractApplicationContext#finishRefresh:

整個容器初始化完畢之后,會在這里進行一些掃尾作業,如清理快取,初始化生命周期處理器,發布容器重繪事件等,

protected void finishRefresh() {
	// Clear context-level resource caches (such as ASM metadata from scanning).
	// 清理快取
	clearResourceCaches();

	// Initialize lifecycle processor for this context.
	// 初始化和生命周期有關的后置處理器
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	// 拿到前面定義的生命周期處理器【LifecycleProcessor】回呼 onRefresh() 方法
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	// 發布容器重繪完成事件
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	LiveBeansView.registerApplicationContext(this);
}

執行流程小結:

  • (1)initLifecycleProcessor():初始化和生命周期有關的后置處理器:默認從容器中找是否有lifecycleProcessor的組件【LifecycleProcessor】,如果沒有,則創建一個DefaultLifecycleProcessor()加入到容器;
  • (2)getLifecycleProcessor().onRefresh():拿到前面定義的生命周期處理器(LifecycleProcessor)回呼onRefresh()方法
  • (3)publishEvent(new ContextRefreshedEvent(this)):發布容器重繪完成事件;
  • (4)liveBeansView.registerApplicationContext(this);

文章總結自:https://juejin.cn/post/6906637797080170510#comment

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

標籤:java

上一篇:Springboot validation 校驗方法

下一篇:Java8 Optional的使用詳解

標籤雲
其他(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