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

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

2023-06-27 07:28:55 後端開發

本文將通過閱讀AnnotationConfigApplicationContext原始碼,分析Spring啟動流程,

創建AnnotationConfigApplicationContext

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(XxConfig.class);
applicationContext.register(YyConfig.class);
applicationContext.refresh();

XxService xxService = applicationContext.getBean(XxService.class);

核心的啟動邏輯都在refresh方法中,

構造方法

public AnnotationConfigApplicationContext() {
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

AnnotatedBeanDefinitionReader類

定義了多個register方法,用于向Spring容器注冊BeanDefinition,

在創建AnnotatedBeanDefinitionReader時,會向容器注冊幾個注解驅動處理器:

  • org.springframework.context.annotation.internalConfigurationAnnotationProcessor: ConfigurationClassPostProcessor
    • BeanFactoryPostProcessor實作,用于決議@Configuration類,
    • 按優先級排序,因為在@Configuration類中宣告的任何@Bean方法都必須在任何其他BeanFactoryPostProcessor執行之前注冊其對應的BeanDefinition,
  • org.springframework.context.annotation.internalAutowiredAnnotationProcessor: AutowiredAnnotationBeanPostProcessor
    • BeanPostProcessor實作類,
    • @Autowired支持處理器,
  • org.springframework.context.annotation.internalCommonAnnotationProcessor: CommonAnnotationBeanPostProcessor
    • BeanPostProcessor實作類,
    • 支持Resource、PostConstruct、PreDestroy等注解,
  • org.springframework.context.event.internalEventListenerProcessor: EventListenerMethodProcessor
  • org.springframework.context.event.internalEventListenerFactory: DefaultEventListenerFactory

ClassPathBeanDefinitionScanner類

BeanDefinition掃描器,在類路徑上檢測Bean,并將其注冊到Spring容器中,掃描的類是通過型別過濾器檢測到的,

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.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			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();
		} catch (BeansException ex) {

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		} finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

prepareRefresh方法

Prepare this context for refreshing, setting its startup date and active flag as well as performing any initialization of property sources.

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.
	// Replace any stub property sources with actual instances.
	// web相關的ApplicationContext有實作
	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方法

Tell the subclass to refresh the internal bean factory.

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	return getBeanFactory();
}

由于AnnotationConfigApplicationContext繼承了GenericApplicationContext類,所以此處獲取到的是DefaultListableBeanFactory物件,

prepareBeanFactory方法

配置BeanFactory的標準背景關系,例如背景關系的ClassLoader和后置處理器,

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Tell the internal bean factory to use the context's class loader etc.
	beanFactory.setBeanClassLoader(getClassLoader());

	// Standard implementation of the BeanExpressionResolver interface,
	// parsing and evaluating Spring EL using Spring's expression module.
	beanFactory.setBeanExpressionResolver(
        new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	// 支持EnvironmentAware, MessageSourceAware, ApplicationContextAware等
	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 interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean.
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// ApplicationListenerDetector處理器自動將ApplicationListener型別Bean添加容器
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	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()));
	}

	// 注冊env 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());
	}
}

postProcessBeanFactory方法

Modify the application context's internal bean factory after its standard initialization. All bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for registering special BeanPostProcessors etc in certain ApplicationContext implementations.

在標準初始化之后修改ApplicationContext的內部bean工廠,所有的BeanDefinition都將被加載,但還沒有任何Bean被實體化,這允許在某些ApplicationContext實作中注冊特殊的BeanPostProcessors等,

invokeBeanFactoryPostProcessors方法

實體化并呼叫注冊的所有BeanFactoryPostProcessor,如果指定順序則按照順序呼叫,必須在單例實體化之前呼叫,

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	// 呼叫BeanFactoryPostProcessors
	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()));
	}
}

呼叫BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,

registerBeanPostProcessors方法

實體化并注冊所有BeanPostProcessor,如果指定順序則按照順序注冊,必須在應用Bean實體化之前呼叫,

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

把BeanPostProcessor實體添加到beanPostProcessors中:

  1. 從容器獲取所有的BeanPostProcessor Bean
  2. 按照以下順序注冊:實作了PriorityOrdered介面、實作了Ordered介面、普通BeanPostProcessor、實作MergedBeanDefinitionPostProcessor介面
private static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

	for (BeanPostProcessor postProcessor : postProcessors) {
		beanFactory.addBeanPostProcessor(postProcessor);
	}
}

initMessageSource方法

國際化,

protected void initMessageSource() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
		this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
		// Make MessageSource aware of parent MessageSource.
		if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
			HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
			if (hms.getParentMessageSource() == null) {
				// Only set parent context as parent MessageSource if no parent MessageSource
				// registered already.
				hms.setParentMessageSource(getInternalParentMessageSource());
			}
		}
	} else {
		// Use empty MessageSource to be able to accept getMessage calls.
		DelegatingMessageSource dms = new DelegatingMessageSource();
		dms.setParentMessageSource(getInternalParentMessageSource());
		this.messageSource = dms;
		beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
	}
}

initApplicationEventMulticaster方法

初始化ApplicationEventMultimaster,如果Context中未定義,則使用SimpleApplicationEventMultimaster,

protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		this.applicationEventMulticaster = beanFactory.getBean(
            APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
	} else {
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.registerSingleton(
            APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
	}
}

onRefresh方法

可以重寫的模板方法,以添加指定的重繪邏輯,在初始化特殊Bean時呼叫,在實體化單例之前呼叫,

默認什么都不做,

SpringBoot中的ServletWebServerApplicationContext實作類在這個階段創建WebServer,

registerListeners方法

添加實作ApplicationListener的Bean作為偵聽器,不會影響其他偵聽器,這些偵聽器可以在不使用Bean的情況下添加,

finishBeanFactoryInitialization方法

完成Bean工廠的初始化,初始化所有剩余的單例Bean,

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize conversion service for this context.
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// Register a default embedded value resolver if no bean post-processor
	// (such as a PropertyPlaceholderConfigurer bean) registered any before:
	// at this point, primarily for resolution in annotation attribute values.
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	beanFactory.freezeConfiguration();

	// Instantiate all remaining (non-lazy-init) singletons.
	beanFactory.preInstantiateSingletons();
}

finishRefresh方法

完成重繪作業,呼叫LifecycleProcessor的onRefresh()方法并發布ContextRefreshedEvent事件,

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.
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

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

啟動流程

  1. 創建AnnotationConfigApplicationContext物件
    • 創建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
    • 向容器注冊幾個注解驅動處理器:ConfigurationClassPostProcessor, AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor等
  2. 呼叫applicationContext.register(XxConfig.class)注冊配置類
  3. 呼叫refresh()方法:
    • prepareRefresh方法準備作業:初始化PropertySources、validateRequiredProperties等
    • Refresh the internal beanFactory
    • 配置BeanFactory的標準背景關系,例如背景關系的ClassLoader和后置處理器
    • 實體化并呼叫注冊的所有BeanFactoryPostProcessor,如果指定順序則按照順序呼叫,必須在單例實體化之前呼叫
    • 實體化并注冊所有BeanPostProcessor,如果指定順序則按照順序注冊,必須在應用Bean實體化之前呼叫
    • 初始化MessageSource
    • 初始化ApplicationEventMultimaster,如果Context中未定義,則使用SimpleApplicationEventMultimaster
    • onRefresh方法,SpringBoot中的ServletWebServerApplicationContext實作類在這個階段創建WebServer
    • 添加實作ApplicationListener的Bean作為偵聽器
    • 完成Bean工廠的初始化,初始化所有剩余的單例Bean
    • 完成重繪作業,呼叫LifecycleProcessor的onRefresh()方法并發布ContextRefreshedEvent事件

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

標籤:Java

上一篇:圖文示例二叉樹的編碼實作程序

下一篇:返回列表

標籤雲
其他(161623) Python(38248) JavaScript(25514) Java(18261) C(15238) 區塊鏈(8272) C#(7972) AI(7469) 爪哇(7425) MySQL(7269) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2437) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1985) HtmlCss(1972) 功能(1967) Web開發(1951) C++(1942) 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
最新发布
  • spring啟動流程 (1) 流程概覽

    本文將通過閱讀AnnotationConfigApplicationContext原始碼,分析Spring啟動流程。 # 創建AnnotationConfigApplicationContext ```java AnnotationConfigApplicationContext applicatio ......

    uj5u.com 2023-06-27 07:28:55 more
  • 圖文示例二叉樹的編碼實作程序

    在上一篇文章中,帶大家一起學習認識了樹型資料結構的定義和特點,并特別介紹了二叉樹的遍歷操作,分別有:前序遍歷、中序遍歷、后序遍歷。前中后的核心區別是根據根節點在遍歷程序中的位置決定的,即:根節點在最前面的稱之為中序遍歷,根節點在中間的稱之為中序遍歷,根節點在最后的稱之為后序遍歷。需要大家掌握根據樹形... ......

    uj5u.com 2023-06-26 09:45:45 more
  • [ARM 匯編]高級部分—ARM匯編編程實戰—3.3.2 嵌入式開發環境搭

    搭建一個嵌入式開發環境主要包括以下幾個部分: 1. 安裝交叉編譯器 2. 配置集成開發環境(IDE) 3. 安裝除錯工具 4. 下載和燒錄程式 接下來,我們將詳細介紹每個部分,并提供相應的實體。 1. **安裝交叉編譯器** 交叉編譯器是用于將您撰寫的ARM匯編代碼編譯成可執行檔案的工具。在本教程中 ......

    uj5u.com 2023-06-26 09:40:32 more
  • 圖文示例二叉樹的編碼實作程序

    在上一篇文章中,帶大家一起學習認識了樹型資料結構的定義和特點,并特別介紹了二叉樹的遍歷操作,分別有:前序遍歷、中序遍歷、后序遍歷。前中后的核心區別是根據根節點在遍歷程序中的位置決定的,即:根節點在最前面的稱之為中序遍歷,根節點在中間的稱之為中序遍歷,根節點在最后的稱之為后序遍歷。需要大家掌握根據樹形... ......

    uj5u.com 2023-06-26 09:39:33 more
  • SpringMVC

    [TOC] # SpringMVC ssm mybatis+Spring+Spring+MVC MVC三層架構 spring : IOC 和 AOP Spring: spring執行流程! # 1、什么是SpringMVC Spring MVC是Spring Framework的一部分,是基于Jav ......

    uj5u.com 2023-06-26 08:00:44 more
  • [ARM 匯編]高級部分—ARM匯編編程實戰—3.3.3 嵌入式應用程式設

    在本章節中,我們將學習如何使用ARM匯編撰寫一個簡單的嵌入式應用程式。我們將以STM32F103微控制器為例,撰寫一個程式,實作按下按鈕時點亮LED的功能。 1. **硬體連接** 首先,我們需要將STM32F103微控制器的一個GPIO引腳連接到LED(通過一個合適的電阻),另一個GPIO引腳連接 ......

    uj5u.com 2023-06-26 08:00:35 more
  • C++面試八股文:std::array如何實作編譯器排序?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第25面: > 面試官:`array`熟悉嗎? > > 二師兄:你說的是原生陣列還是`std::array`? > > 面試官:你覺得兩者有什么區別? > > 二師兄:區別不是很大,原生陣列(非動態陣列)和std::array都在堆疊上開辟空間,初始化 ......

    uj5u.com 2023-06-26 08:00:30 more
  • celery筆記七之周期/定時任務及crontab定義

    > 本文首發于公眾號:Hunter后端 > 原文鏈接:[celery筆記七之周期/定時任務及crontab定義](https://mp.weixin.qq.com/s/sNShaRbuM2gm2qn_codaTg) periodic task,即為周期,或者定時任務,比如說每天晚上零點零分需要運行一 ......

    uj5u.com 2023-06-26 08:00:23 more
  • 逍遙自在學C語言 | 指標陷阱-空指標與野指標

    ## 前言 在C語言中,指標是一種非常強大和靈活的工具,但同時也容易引發一些問題,其中包括空指標和野指標。 本文將帶你了解這兩個概念的含義、產生原因以及如何避免它們所導致的問題。 ## 一、人物簡介 - 第一位閃亮登場,有請今后會一直教我們C語言的老師 —— 自在。 ![](https://img2 ......

    uj5u.com 2023-06-26 08:00:11 more
  • 分享一些我技術成長的感悟

    今晚來聊聊我在**技術成長**中的一些感悟,跟大家分享下。 ## BALABALA 在大學的時候,我一個計算機專業相關的證書都沒考,自認為這些證書對我以后找作業沒什么大的幫助。于是我把時間更多地花在研究八股文上,因為八股文在面試的時候是要用到的。 (**利益化**) > **我會對我做的事情利益化* ......

    uj5u.com 2023-06-26 08:00:04 more