spring框架4 - bean加载

本节内容:beanFactory.getBean("user");

java 复制代码
    @Test
    void testGetBean() {
        Gun gun = beanFactory.getBean("m416", Gun.class);
        log.info("gun={}", gun);
    }
java 复制代码
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	return this.doGetBean(name, requiredType, (Object[])null, false);
}
java 复制代码
	/**
	 * 返回指定bean的一个实例,该实例可以是共享的,也可以是独立的
	 */
	// eg1:name="m416",requiredType=Gun.class,args=null,typeCheckOnly=false
	@SuppressWarnings("unchecked")
	protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
		// 提取真正的beanName(去除'&'或者将别名name转化为beanName)
		String beanName = transformedBeanName(name); // eg1:beanName="m416"

		/** 1:尝试根据beanName,从缓存中获得单例对象 */
		Object beanInstance, sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null)  // eg1:sharedInstance=null
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); // 从bean中获得真正的实例对象

		/** 2:缓存中不存在实例,则采取自主创建实例对象 */
		else {
			// 如果当前bean是正在创建中的原型对象,则直接抛出异常
			if (isPrototypeCurrentlyInCreation(beanName)) // eg1:false
				throw new BeanCurrentlyInCreationException(beanName);

			/** 3:如果存在parentBeanFactory 并且 配置中也没有beanName的配置信息,则尝试从parentBeanFactory中获取实例 */
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // eg1:parentBeanFactory=null
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory)
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
				else if (args != null)
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				else if (requiredType != null)
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				else
					return (T) parentBeanFactory.getBean(nameToLookup);
			}

			// 如果不执行类型检查,则将beanName保存到alreadyCreated缓存中
			if (!typeCheckOnly) // eg1:true
				markBeanAsCreated(beanName);

			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);
			try {
				if (requiredType != null) // eg1:requiredType=Gun.class
					beanCreation.tag("beanType", requiredType::toString);

				/** 4:将GenericBeanDefinition转换为RootBeanDefinition,如果是子Bean,则与父类的相关属性进行合并 */
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args); // eg1:mbd=RootBeanDefinition@2607

				/** 5:如果存在依赖,那么需要递归每一个依赖的bean并对其进行实例化创建 */
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) { // eg1:dependsOn=null
					for (String dep : dependsOn) {
						// 如果发生了循环依赖,则直接抛出异常
						if (isDependent(beanName, dep))
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");

						registerDependentBean(dep, beanName);
						try {
							getBean(dep); // 创建每一个依赖(dep)的实例Bean
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				/** 6:创建bean的单例实例对象 */
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args); // eg1:return Gun@2334
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					// eg1:AbstractAutowireCapableBeanFactory#getObjectForBeanInstance
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				/** 7:创建原型对象 */
				else if (mbd.isPrototype()) {
					Object prototypeInstance;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				/** 8:创建指定scope类型的对象 */
				else {
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName))
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");

					Scope scope = this.scopes.get(scopeName);
					if (scope == null)
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");

					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
			}
			catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally {
				beanCreation.end(); // eg1:DefaultApplicationStartup#end()
			}
		}

		/** 9:检查需要的类型是否符合bean的实际类型,如果不同,则对其进行类型转换 */
		return adaptBeanInstance(name, beanInstance, requiredType); // eg1:return Gun@2334
	}

// 提取真正的beanName(去除'&'或者将别名name转化为beanName)

java 复制代码
// 提取真正的beanName(去除'&'或者将别名name转化为beanName)
String beanName = transformedBeanName(name); // eg1:beanName="m416"
java 复制代码
/**
 * 返回bean名称,必要时去掉工厂引用前缀,并将别名解析为规范名称
 */
// eg1:name="m416"
protected String transformedBeanName(String name) {
	return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
java 复制代码
/**
 * 返回实际的bean名称,去掉工厂解引用前缀(如果有,也去掉重复的工厂前缀)
 */
// eg1:name="m416"
public static String transformedBeanName(String name) {
	Assert.notNull(name, "'name' must not be null");

	// 如果不是"&"前缀,则直接返回name即可
	if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) // eg1:true
		return name; // eg1:return "m416"

	// 去掉所有前缀"&",只返回beanName
	return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
		do {
			beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
		}
		while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
		return beanName;
	});
}
java 复制代码
/**
 * 确定原始名称,将别名解析为规范名称
 */
// eg1:name="m416"
public String canonicalName(String name) {
	String canonicalName = name;
	String resolvedName;
	do {
		// eg1:result = {ConcurrentHashMap@2355}  size = 5
		// 			"com.muse.springdemo.beanpostprocessor.MuseBeanPostProcessor" -> "com.muse.springdemo.beanpostprocessor.MuseBeanPostProcessor#0"
		// 			"org.springframework.web.servlet.view.InternalResourceViewResolver" -> "org.springframework.web.servlet.view.InternalResourceViewResolver#0"
		// 			"muse" -> "customUser"
		// 			"alias_ent" -> "ent"
		// 			"org.springframework.beans.factory.config.CustomEditorConfigurer" -> "org.springframework.beans.factory.config.CustomEditorConfigurer#0"
		/** 从别名中寻找原始名称 */
		resolvedName = this.aliasMap.get(canonicalName);
		if (resolvedName != null) // eg1:resolvedName=null
			canonicalName = resolvedName;
	}
	while (resolvedName != null);
	return canonicalName; // eg1:return "m416"
}

/** 1:尝试根据beanName,从缓存中获得单例对象 */

/** 2:缓存中不存在实例,则采取自主创建实例对象 */

// 如果当前bean是正在创建中的原型对象,则直接抛出异常

/** 3:如果存在parentBeanFactory 并且 配置中也没有beanName的配置信息,则尝试从parentBeanFactory中获取实例 */

// 如果不执行类型检查,则将beanName保存到alreadyCreated缓存中

/** 4:将GenericBeanDefinition转换为RootBeanDefinition,如果是子Bean,则与父类的相关属性进行合并 */

/** 5:如果存在依赖,那么需要递归每一个依赖的bean并对其进行实例化创建 */

// 如果发生了循环依赖,则直接抛出异常

/** 6:创建bean的单例实例对象 */

/** 7:创建原型对象 */

/** 8:创建指定scope类型的对象 */

/** 9:检查需要的类型是否符合bean的实际类型,如果不同,则对其进行类型转换 */

相关推荐
baiduopenmap3 分钟前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish11 分钟前
小程序webview我爱死你了 小程序webview和H5通讯
前端
不是二师兄的八戒15 分钟前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
请叫我欧皇i23 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_26 分钟前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
爱编程的小生26 分钟前
Easyexcel(2-文件读取)
java·excel
guokanglun32 分钟前
空间数据存储格式GeoJSON
前端
带多刺的玫瑰43 分钟前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
zhang-zan1 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium
猫爪笔记1 小时前
前端:HTML (学习笔记)【2】
前端·笔记·学习·html