Spring 依赖注入(DI) 源码解析

news/2025/2/25 16:13:25

引言

概述: Spring Bean 创建源码分析系列

【1】Spring Bean 的实例化过程源码解析
【2】Spring 依赖注入(DI) 源码解析
【3】Spring 三级缓存解决循环依赖

1 工程

在这里插入图片描述

1.1 StudentController

@Controller
public class StudentController {

    @Autowired
    private StudentService studentService;

    public StudentController(){
        System.out.println("StudentController invoke NoArgsConstructor");
    }

}

1.2 StudentService

@Service
public class StudentService {



}

1.3 applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="false">

    <context:component-scan base-package="com.rosh.controller,com.rosh.service"/>


</beans>

1.4 RoshTest

public class RoshTest {

    @Test
    public void mainTest(){
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        applicationContext.close();

    }

}

2 核心方法

类:AbstractAutowireCapableBeanFactory

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {

			/**
			 * 【1】创建实例
			 */
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					/**
					 *【2】 收集有注解的属性、方法。
					 *
					 * 1 AutowiredAnnotationBeanPostProcessor 扫描 @Autowired、@Value注解
					 * 2 CommonAnnotationBeanPostProcessor 扫描 @PostConstruct、@Resource、@preDestroy
					 */
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			/**
			 * 【3】 添加三级缓存,解决循环依赖
			 */
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {

			/**
			 * 【4】 依赖注入
			 */
			populateBean(beanName, mbd, instanceWrapper);

			/**
			 * 【5】 初始化bean
			 */
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

3 创建实例

详情请看:
Spring Bean 的实例化过程源码解析
在这里插入图片描述

4 收集注解

在这里插入图片描述
描述: AutowiredAnnotationBeanPostProcessor完成注解的收集
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 反射完成依赖注入

在这里插入图片描述

描述: AutowiredAnnotationBeanPostProcessor完成依赖注入

在这里插入图片描述
描述: 从缓存中获取meta信息
在这里插入图片描述
在这里插入图片描述
描述: 用反射完成 依赖注入
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6 Bean实例初始化

描述: 加强bean
在这里插入图片描述
在这里插入图片描述


http://www.niftyadmin.cn/n/4556655.html

相关文章

c语言的 a++ 和 ++a有什么区别

||| 如果要打印的值是a如printf("%d" 然后等结束本句的时候加一&#xff08;先使用后加一&#xff09;而a值等于a1 再打印出来.具体差别你可以自己试着运行比较一下. a);那打印出来的只是A的值.但是第二次打印的A值就是后的值.就是先打印后;A就是先改变A的值 a是先把…

vim 安装molokai主题

在.vim文件夹下创建文件夹colors 进入 https://github.com/tomasr/molokai 下载molokai.vim 将其放入colors文件夹下 进入.vimrc中 添加 " 代码颜色主题 syntax on syntax enable set t_Co256 colorscheme molokai 重新打开vim&#xff0c;就会发现主题已经变了。 转载于:…

(C语言) 怎么用代码实现一个学生成绩管理系统

||| 用C语言的话界面应该不会很好看吧. ||| 需求分析清楚 595387031 ||| 大哥你为什么要用C语言实现 要的话我从QQ上发给你好了 程序发不上来 问问说我的回答重复的字数太多了 它用来操纵数据库可不是太理想哦 代码不过是积木

Spring Aop初始化源码分析

引言 概述&#xff1a; AOP系列文章&#xff1a; 【1】Spring Aop初始化源码分析 【2】Spring AOP创建代理对象源码解析 【3】Spring AOP 链式调用过程源码解析 【4】Spring 事务执行过程源码解析 1 工程简介 1.1 pom <properties><project.build.sourceEncoding&g…

判断有向图是否有环

如何判断有向图是否有环 1.dfs,bfs2.拓扑排序使用拓扑排序来解决这个问题&#xff0c;首先什么是拓扑排序&#xff1f;一直删除出度为0的顶点直到没有出度为0的顶点&#xff0c;如果最终还有顶点存在就说明有环&#xff0c;并且是由剩下的顶点组成的环。 例如 有有向图的邻接表…

C语言中的小数如果用int形式输出

如果想进行四舍五入 而是直接读取该浮点数所在内存 并没有对浮点数进行强制转换 在调用printf时 1.6); return 0;}会得到如下运行结果&#xff1a;-17179869180x9999999APress any key to continue由此可见 ||| 如果执行如下程序&#xff1a;int main(int argc 得到的结果应该是…

Spring AOP创建代理对象源码解析

引言 概述&#xff1a; AOP系列文章&#xff1a; 【1】Spring Aop初始化源码分析 【2】Spring AOP创建代理对象源码解析 【3】Spring AOP 链式调用过程源码解析 【4】Spring 事务执行过程源码解析 1 工程简介 1.1 pom <properties><project.build.sourceEncoding>…

1.处理当前时间前后的日期范围 2.处理日期格式

Month(month) {//处理当前时间前后的日期范围 var time new Date(); time.setDate(time.getDate());//获取Day天后的日期 var y time.getFullYear(); var m; if (time.getMonth() month 1>12){ y y1; m time.getMonth() month - 11;//获…