主頁 > 後端開發 > spring啟動流程 (3) BeanDefinition詳解

spring啟動流程 (3) BeanDefinition詳解

2023-07-04 09:47:47 後端開發

BeanDefinition在Spring初始化階段保存Bean的元資料資訊,包括Class名稱、Scope、構造方法引數、屬性值等資訊,本文將介紹一下BeanDefinition介面、重要的實作類,以及在Spring中的使用示例,

BeanDefinition介面

用于描述了一個Bean實體,該Bean實體具有屬性、構造方法引數以及由具體實作提供的其他資訊,

這是一個基礎介面:主要目的是允許BeanFactoryPostProcessor獲取和修改Bean實體屬性和其他元資料,

封裝以下資訊:

  • ParentName - The name of the parent definition of this bean definition.
  • BeanClassName - The bean class name of this bean definition. The class name can be modified during bean factory post-processing, typically replacing the original class name with a parsed variant of it.
  • Scope - Override the target scope of this bean, specifying a new scope name.
  • isLazyInit - Whether this bean should be lazily initialized.
  • DependsOn - The names of the beans that this bean depends on being initialized. The bean factory will guarantee that these beans get initialized first.
  • AutowireCandidate - Whether this bean is a candidate for getting autowired into some other bean.
  • Primary - Whether this bean is a primary autowire candidate.
  • FactoryBeanName - The factory bean to use. This the name of the bean to call the specified factory method on.
  • FactoryMethodName - Specify a factory method, if any. This method will be invoked with constructor arguments, or with no arguments if none are specified. The method will be invoked on the specified factory bean, if any, or otherwise as a static method on the local bean class.
  • ConstructorArgumentValues - Constructor argument values for this bean.
  • PropertyValues - The property values to be applied to a new instance of the bean.
  • InitMethodName - The name of the initializer method.
  • DestroyMethodName - The name of the destroy method.
  • Role - The role hint for this BeanDefinition. The role hint provides the frameworks as well as tools an indication of the role and importance of a particular BeanDefinition.
  • ResolvableType - A resolvable type for this bean definition, based on the bean class or other specific metadata.
  • isSingleton - Whether this a Singleton, with a single, shared instance returned on all calls.
  • isPrototype - Whether this a Prototype, with an independent instance returned for each call.
  • isAbstract - Whether this bean is "abstract", that is, not meant to be instantiated.
  • OriginatingBeanDefinition - The originating BeanDefinition.

AbstractBeanDefinition類

實作了BeanDefinition介面,具體的、完整的BeanDefinition基類,抽取出GenericBeanDefinition、RootBeanDefinition和ChildBeanDefinition的公共屬性,

擴展的屬性:

  • AutowireMode - The autowire mode. This determines whether any automagical detection and setting of bean references will happen. Default is AUTOWIRE_NO which means there won't be convention-based autowiring by name or type (however, there may still be explicit annotation-driven autowiring).
    • AUTOWIRE_NO
    • AUTOWIRE_BY_NAME
    • AUTOWIRE_BY_TYPE
    • AUTOWIRE_CONSTRUCTOR
    • AUTOWIRE_AUTODETECT

RootBeanDefinition類

繼承AbstractBeanDefinition類,

RootBeanDefinition表示在運行時支持BeanFactory中指定Bean的合并BeanDefinition,它可能是由多個相互繼承的原始BeanDefinition創建的,通常注冊為GenericBeanDefinitions,RootBeanDefinition本質上是運行時的"統一"RootBeanDefinition視圖,

RootBeanDefinition也可以用于在配置階段注冊各個BeanDefinition,然而,自Spring2.5以來,以編程方式注冊BeanDefinition的首選方式是GenericBeanDefinition類,GenericBeanDefinition的優勢是允許動態定義父依賴項,而不是將角色硬編碼為RootBeanDefinition,

擴展的屬性:

  • DecoratedDefinition - Target definition that is being decorated by this bean definition.
  • QualifiedElement - Specify the AnnotatedElement defining qualifiers, to be used instead of the target class or factory method.
  • TargetType - Specify a generics-containing target type of this bean definition, if known in advance.
  • stale - Determines if the definition needs to be re-merged.
  • allowCaching
  • isFactoryBean

GenericBeanDefinition類

繼承AbstractBeanDefinition類,

GenericBeanDefinition是用于構建標準BeanDefinition的一站式組件,與其他BeanDefinition一樣,它允許指定一個類以及可選的構造方法引數和屬性,另外,從父BeanDefinition派生可以通過parentName屬性靈活配置,

通常,使用GenericBeanDefinition類來注冊用戶可見的BeanDefinition,后置處理器可能會對其進行操作,甚至可能重新配置parentName屬性,如果父子關系恰好是預先確定的,請使用RootBeanDefinition和ChildBeanDefinition,

AnnotatedBeanDefinition介面

繼承BeanDefinition介面,

擴展BeanDefinition介面,提供Bean的AnnotationMetadata,而不需要加載該類,

public interface AnnotatedBeanDefinition extends BeanDefinition {

	/**
	 * Obtain the annotation metadata (as well as basic class metadata)
	 * for this bean definition's bean class.
	 */
	AnnotationMetadata getMetadata();

	/**
	 * Obtain metadata for this bean definition's factory method, if any.
	 */
	MethodMetadata getFactoryMethodMetadata();
}

ScannedGenericBeanDefinition類

GenericBeanDefinition類的擴展,基于ASM ClassReader,實作了AnnotatedBeanDefinition介面,可以獲取注解元資料,

這個類不會提前加載Bean Class,它從.class檔案檢索所有相關的元資料,并使用ASM ClassReader進行決議,

public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

	private final AnnotationMetadata metadata;

	/**
	 * Create a new ScannedGenericBeanDefinition for the class that the
	 * given MetadataReader describes.
	 * @param metadataReader the MetadataReader for the scanned target class
	 */
	public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
		this.metadata = https://www.cnblogs.com/xugf/p/metadataReader.getAnnotationMetadata();
		setBeanClassName(this.metadata.getClassName());
		setResource(metadataReader.getResource());
	}

	@Override
	public final AnnotationMetadata getMetadata() {
		return this.metadata;
	}

	@Override
	public MethodMetadata getFactoryMethodMetadata() {
		return null;
	}
}

AnnotatedGenericBeanDefinition類

GenericBeanDefinition類的擴展,實作了AnnotatedBeanDefinition介面,可以獲取注解元資料,

public class AnnotatedGenericBeanDefinition 
		extends GenericBeanDefinition implements AnnotatedBeanDefinition {

	private final AnnotationMetadata metadata;

	private MethodMetadata factoryMethodMetadata;

	public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
		setBeanClass(beanClass);
		this.metadata = https://www.cnblogs.com/xugf/p/AnnotationMetadata.introspect(beanClass);
	}

	public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
		if (metadata instanceof StandardAnnotationMetadata) {
			setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
		} else {
			setBeanClassName(metadata.getClassName());
		}
		this.metadata = metadata;
	}

	public AnnotatedGenericBeanDefinition(
			AnnotationMetadata metadata,
			MethodMetadata factoryMethodMetadata) {
		this(metadata);
		setFactoryMethodName(factoryMethodMetadata.getMethodName());
		this.factoryMethodMetadata = factoryMethodMetadata;
	}


	@Override
	public final AnnotationMetadata getMetadata() {
		return this.metadata;
	}

	@Override
	public final MethodMetadata getFactoryMethodMetadata() {
		return this.factoryMethodMetadata;
	}
}

Spring中使用BeanDefinition示例

注冊componentClasses

AnnotationConfigApplicationContext啟動代碼:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ServiceConfig.class);
applicationContext.refresh();

AnnotationConfigApplicationContext在啟動時可以使用register方法注冊@Configuration類,本小節將從這個方法入手看一個BeanDefinition的使用示例:

public void register(Class<?>... componentClasses) {
	Assert.notEmpty(componentClasses, "At least one component class must be specified");
	this.reader.register(componentClasses);
}

// reader.register(...)
public void register(Class<?>... componentClasses) {
	for (Class<?> componentClass : componentClasses) {
		registerBean(componentClass);
	}
}

private <T> void doRegisterBean(Class<T> beanClass, String name,
		Class<? extends Annotation>[] qualifiers, Supplier<T> supplier,
		BeanDefinitionCustomizer[] customizers) {

	// 構造方法中會決議AnnotationMetadata元資料
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
	// 判斷是否允許裝配
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

	abd.setInstanceSupplier(supplier);
	ScopeMetadata scopeMetadata = https://www.cnblogs.com/xugf/p/this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

	// 決議Lazy,Primary,DependsOn,Role等屬性
	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));
			}
		}
	}
	if (customizers != null) {
		for (BeanDefinitionCustomizer customizer : customizers) {
			customizer.customize(abd);
		}
	}

	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	// 處理Scope的proxyMode
	definitionHolder = AnnotationConfigUtils
        .applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	// 注冊到容器
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

// BeanDefinitionReaderUtils.registerBeanDefinition(...)
public static void registerBeanDefinition(
		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
		throws BeanDefinitionStoreException {

	// Register bean definition under primary name.
	String beanName = definitionHolder.getBeanName();
	// 將Bean注冊到BeanDefinitionRegistry
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// Register aliases for bean name, if any.
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			registry.registerAlias(beanName, alias);
		}
	}
}

此處的registry是AnnotationConfigApplicationContext物件,registerBeanDefinition方法的實作在GenericApplicationContext類:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {
	this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

// beanFactory.registerBeanDefinition(...)
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {

	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			((AbstractBeanDefinition) beanDefinition).validate();
		} catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}

	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
	if (existingDefinition != null) {
		if (!isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
		}
		this.beanDefinitionMap.put(beanName, beanDefinition);
	} else {
		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				removeManualSingletonName(beanName);
			}
		} else {
			// Still in startup registration phase
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			removeManualSingletonName(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}

	if (existingDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	} else if (isConfigurationFrozen()) {
		clearByTypeCache();
	}
}

@Bean注解

@Bean注解注入的Bean最終在ConfigurationClassBeanDefinitionReader的loadBeanDefinitionsForBeanMethod方法注冊BeanDefinition:

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	ConfigurationClass configClass = beanMethod.getConfigurationClass();
	MethodMetadata metadata = https://www.cnblogs.com/xugf/p/beanMethod.getMetadata();
	String methodName = metadata.getMethodName();

	// Do we need to mark the bean as skipped by its condition?
	if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
		configClass.skippedBeanMethods.add(methodName);
		return;
	}
	if (configClass.skippedBeanMethods.contains(methodName)) {
		return;
	}

	AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);

	// Consider name and any aliases
	List names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
	String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

	// Register aliases even when overridden
	for (String alias : names) {
		this.registry.registerAlias(beanName, alias);
	}

	// Has this effectively been overridden before (e.g. via XML)?
	if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
		return;
	}

	// 創建ConfigurationClassBeanDefinition
	// 是RootBeanDefinition的子類
	ConfigurationClassBeanDefinition beanDef = 
        new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
	beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

	if (metadata.isStatic()) {
		// static @Bean method
		if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
			beanDef.setBeanClass(
                ((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
		} else {
			beanDef.setBeanClassName(configClass.getMetadata().getClassName());
		}
		beanDef.setUniqueFactoryMethodName(methodName);
	} else {
		// instance @Bean method
		beanDef.setFactoryBeanName(configClass.getBeanName());
		beanDef.setUniqueFactoryMethodName(methodName);
	}

	if (metadata instanceof StandardMethodMetadata) {
		beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
	}

	beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
	beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
			SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

	AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

	Autowire autowire = bean.getEnum("autowire");
	if (autowire.isAutowire()) {
		beanDef.setAutowireMode(autowire.value());
	}

	boolean autowireCandidate = bean.getBoolean("autowireCandidate");
	if (!autowireCandidate) {
		beanDef.setAutowireCandidate(false);
	}

	String initMethodName = bean.getString("initMethod");
	if (StringUtils.hasText(initMethodName)) {
		beanDef.setInitMethodName(initMethodName);
	}

	String destroyMethodName = bean.getString("destroyMethod");
	beanDef.setDestroyMethodName(destroyMethodName);

	// Consider scoping
	ScopedProxyMode proxyMode = ScopedProxyMode.NO;
	AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
	if (attributes != null) {
		beanDef.setScope(attributes.getString("value"));
		proxyMode = attributes.getEnum("proxyMode");
		if (proxyMode == ScopedProxyMode.DEFAULT) {
			proxyMode = ScopedProxyMode.NO;
		}
	}

	// Replace the original bean definition with the target one, if necessary
	BeanDefinition beanDefToRegister = beanDef;
	if (proxyMode != ScopedProxyMode.NO) {
		BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
				new BeanDefinitionHolder(beanDef, beanName), this.registry,
				proxyMode == ScopedProxyMode.TARGET_CLASS);
		beanDefToRegister = new ConfigurationClassBeanDefinition(
				(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
	}

	this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

@ComponentScan注解

支持@ComponentScan注解的最終邏輯在ClassPathScanningCandidateComponentProvider類的scanCandidateComponents方法中:

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (resource.isReadable()) {
				try {
					// 此處獲取到的是SimpleMetadataReader物件,
					// 內部使用ASM決議.class檔案封裝AnnotationMetadata物件
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					// 判斷是一個Component
					if (isCandidateComponent(metadataReader)) {
						// 創建ScannedGenericBeanDefinition物件
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							candidates.add(sbd);
						}
					}
				} catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
		}
	} catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

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

標籤:Java

上一篇:最簡單的人臉檢測(免費呼叫百度AI開放平臺介面)

下一篇:返回列表

標籤雲
其他(162058) Python(38266) JavaScript(25520) Java(18288) C(15238) 區塊鏈(8275) C#(7972) AI(7469) 爪哇(7425) MySQL(7285) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5876) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4610) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2438) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) HtmlCss(1986) .NET技术(1985) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1882) .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啟動流程 (3) BeanDefinition詳解

    BeanDefinition在Spring初始化階段保存Bean的元資料資訊,包括Class名稱、Scope、構造方法引數、屬性值等資訊,本文將介紹一下BeanDefinition介面、重要的實作類,以及在Spring中的使用示例。 # BeanDefinition介面 用于描述了一個Bean實體, ......

    uj5u.com 2023-07-04 09:47:47 more
  • 最簡單的人臉檢測(免費呼叫百度AI開放平臺介面)

    遠程呼叫百度AI開放平臺的web服務,快速完成人臉識別 ### 歡迎訪問我的GitHub > 這里分類和匯總了欣宸的全部原創(含配套原始碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### ......

    uj5u.com 2023-07-04 09:40:35 more
  • SpringBoot對接阿里云OSS上傳檔案以及回呼(有坑)

    ### 前言 今天在對接阿里云OSS物件存盤, 把這程序記錄下來 ### 鏈接 阿里云的內容很多,檔案是真的難找又難懂 本文主要是用的PostObject API 加上 Callback引數 PostObject -> [https://help.aliyun.com/document_detail ......

    uj5u.com 2023-07-04 07:55:34 more
  • 測驗開發-后端開發do物體類創建

    **創建user表物體類** - 新增do目錄下創建user_entity.py和init.py ``` from sqlalchemy import Integer from server import db """ User表的物體類,與DB欄位一致 """ class UserEntity(d ......

    uj5u.com 2023-07-04 07:55:26 more
  • C++面試八股文:如何實作一個strncpy函式?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第31面: > 面試官:`strcpy`函式使用過吧? > > 二師兄:用過。 > > 面試官:這個函式有什么作用? > > 二師兄:主要用做字串復制,將于字符從一個位置復制到另一個位置。 > > 面試官:`strncpy`函式也使用過吧,和`st ......

    uj5u.com 2023-07-04 07:55:17 more
  • jar-project 代碼加殼加密工具【開源】

    開源地址:https://gitee.com/chejiangyi/jar-protect 介紹 java 本身是開放性極強的語言,代碼也容易被反編譯,沒有語言層面的一些常規保護機制,jar包很容易被反編譯和破解。 受classfinal(已停止維護)設計啟發,針對springboot日常專案開發, ......

    uj5u.com 2023-07-04 07:50:00 more
  • Golang起步篇

    # 一. 安裝Go語言開發環境 ## 1. Wondows下搭建Go開發環境 ### (1). 下載SDK工具包 **sdk下載地址為:**[__https://go.dev/dl/__](https://go.dev/dl/) ![](https://tcs-devops.aliyuncs.com ......

    uj5u.com 2023-07-04 07:44:07 more
  • 解決Springboot專案打成jar包后獲取resources目錄下的檔案報錯的

    前幾天在專案讀取resources目錄下的檔案時碰到一個小坑,明明在本地是可以正常運行的,但是一發到測驗環境就報錯了,說找不到檔案,報錯資訊是:class path resource [xxxx] cannot be resolved to absolute file path because it... ......

    uj5u.com 2023-07-04 07:43:14 more
  • Python web 框架對比:Flask vs Django

    哈嘍大家好,我是咸魚 今天我們從幾個方面來比較一些現在流行的兩個 python web 框架——Flask 和 Django,突出它們的主要特性、優缺點和簡單案例 到最后,大家將更好地了解哪個框架更適合自己的特定需求 參考鏈接:https://djangocentral.com/flask-vs-d ......

    uj5u.com 2023-07-04 07:43:02 more
  • GO 語言中 chan 的理解

    GO 語言中 chan 的理解 ### chan 的底層實作是怎么樣的? > chan 是 Go 語言中的一個關鍵字,用于實作并發通信。chan 可以用于在不同的 goroutine 之間傳遞資料,實作資料的同步和異步傳輸。 在底層實作上,chan 是通過一個結構體來表示的,這個結構體包含了一個指向 ......

    uj5u.com 2023-07-04 07:42:58 more