Spring Bean 的实例化过程源码解析

news/2024/7/7 18:33:42

引言

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

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

1 工程概述

在这里插入图片描述

1.1 pom

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.2.8.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
        <!-- 日志相关依赖 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.10</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>

1.2 bean

@Data
@Component
public class CqCityBean {

    private static final String NAME = "重庆";

    public String getCityName(){

        return NAME;
    }

}

@Data
public class StudentBean {

    public final String name = "rosh";

    public final Integer age = 18;

    public StudentBean(){

        System.out.println("invoke StudentBean NoArgsConstructor");

    }

}
 
 
@Data
@Component
public class XaCityBean {

    private static final String NAME = "西安";

    public String getCityName(){

        return NAME;
    }

}


1.3 service

@Service
public class CityService {

    @Autowired
    public CityService(CqCityBean cq, XaCityBean xa) {
        System.out.println(cq.getCityName());
        System.out.println(xa.getCityName());
    }

}

1.4 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.service,com.rosh.bean"/>

    <bean id="student" class="com.rosh.bean.StudentBean"/>

</beans>

1.5 RoshTest

public class RoshTest {

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

    }

}

1.6 运行结果

在这里插入图片描述

2 主流程源码Debug

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

主流程时序图:
在这里插入图片描述

3 createBeanInstance 源码解析

描述: 该方法主要作用bean的构造方法创建对象

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		//如果有FactoryMethodName属性
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?

		/**
		 * 【1】实例化Bean带有@Autowired注解的构造函数
		 *
		 * (1) 找到带有@Autowired注解的有参构造函数
		 * (2) 使用构造函数创建对象
		 */
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// 调用无参构造方法创建bean
		return instantiateBean(beanName, mbd);
	}

3.1 创建无参bean对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
描述: 使用反射调用无参构造函数创建对象
在这里插入图片描述
在这里插入图片描述

3.2 @Autowired构造创建有参对象

在这里插入图片描述
在这里插入图片描述

3.2.1 AutowiredAnnotationBeanPostProcessor

determineCandidateConstructors 方法分析,获取@Autowired 有参构造函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2.2 ConstructorResolver

ConstructorResolver类autowireConstructor方法创建对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
描述: 创建参数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 无@Autowired 构造创建有参对象

在这里插入图片描述
在这里插入图片描述

3.3.1 Debug

在这里插入图片描述

AutowiredAnnotationBeanPostProcessor 检查:
在这里插入图片描述
在这里插入图片描述


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

相关文章

爬虫--Scrapy框架课程介绍

Scrapy框架课程介绍&#xff1a; 框架的简介和基础使用持久化存储代理和cookie日志等级和请求传参CrawlSpider基于redis的分布式爬虫一scrapy框架的简介和基础使用 a) 概念&#xff1a;为了爬取网站数据而编写的一款应用框架&#xff0c;出名&#xff0c;强大。所谓的框…

关于c语言的一些问题

这样就有默认值了 只要最后包在“ ”中就行了 答案补充 加一个system("y");在原来的那个后面看看 ||| 赋值给变量 system("format d: /y")&#xff1b; ||| 语句应该有&#xff1b;结尾system("format d:")&#xff1b;要设置参数的话直接和dos命…

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

引言 概述&#xff1a; Spring Bean 创建源码分析系列 【1】Spring Bean 的实例化过程源码解析 【2】Spring 依赖注入(DI) 源码解析 【3】Spring 三级缓存解决循环依赖 1 工程 1.1 StudentController Controller public class StudentController {Autowiredprivate Student…

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;并且是由剩下的顶点组成的环。 例如 有有向图的邻接表…