爱上源码,重学 Spring 之 IoC 深入源码

本文主要介绍了Spring源码阅读技巧,特别是IoC初始化流程和解决循环依赖的方法。通过ClassPathXmlApplicationContext入口,深入探讨了bean工厂的构建,包括预刷新、创建bean工厂、后置处理器等关键步骤。此外,还分析了Spring如何通过三级缓存解决循环依赖问题,以及在IoC中应用的设计模式,如工厂、模板和观察者模式。
摘要由CSDN通过智能技术生成
回答:
我们为什么要学习源码?
1、知其然知其所以然
2、站在巨人的肩膀上,提高自己的编码水平
3、应付面试

 

1.1 Spring 源码阅读小技巧

1、类层次藏得太深,不要一个类一个类的去看,遇到方法该进就大胆的进

2、更不要一行一行的去看,看核心点,有些方法并不重要,不要跟它纠缠

3、看不懂的先不看,根据语义和返回值能知道这个方法达到了啥目的即可

4、只看核心接口(下面标注了重点的地方)和核心代码,有些地方也许你使用 spring 以来都没触发过

5、debug 跟步走,源码中给大家标注好了,见到 ”===>“ 就进去

​ 进去之前,下一行打个断点,方便快速回到岔路口

​ 进去之前,可以先点方法看源码,再 debug 跟进

6、广度优先,而非深度优先。先沿着主流程走,了解大概,再细化某些方法

7、认命。spring 里多少万行的代码,一部书都写不完。只能学关键点

阅读源码目的

加深理解 spring 的 bean 加载过程

面试吹牛 x

江湖传说,spring 的类关系是这样的……

1.2 IoC 初始化流程与继承关系

引言
在看源码之前需要掌握Spring的继承关系和初始化

1) IoC 容器初始化流程

目标:

1、IoC 容器初始化过程中到底都做了哪些事情(宏观目标)

2、IoC 容器初始化是如何实例化 Bean 的(划重点,最终目标)

//没有Spring之前我们是这样的
User user=new User();
user.xxx();

//有了Spring之后我们是这样的
<bean id="userService" class="com.spring.test.impl.UserServiceImpl">
User user= context.getBean("xxx");
user.xxx();

IoC 流程简化图:

tips:

下面的流转记不住没有关系

在剖析源码的整个过程中,我们一直会拿着这个图和源码对照

初始化:

1、容器环境的初始化

2、Bean 工厂的初始化(IoC 容器启动首先会销毁旧工厂、旧 Bean、创建新的工厂)

读取与定义

读取:通过 BeanDefinitonReader 读取我们项目中的配置(application.xml)

定义:通过解析 xml 文件内容,将里面的 Bean 解析成 BeanDefinition(未实例化、未初始化)

实例化与销毁

Bean 实例化、初始化(注入)

销毁缓存等

扩展点

事件与多播、后置处理器

复杂的流程关键点:

重点总结:

1、工厂初始化过程

2、解析 xml 到 BeanDefinition,放到 map

3、调用后置处理器

4、从 map 取出进行实例化 (ctor.newInstance)

5、实例化后放到一级缓存 (工厂)

2) 容器与工厂继承关系

tips:

别紧张,下面的继承记不住没有关系

关注颜色标注的几个就可以

** 目标:** 简单理解 ioC 容器继承关系

继承关系理解:

1、ClassPathXmlApplicationContext 最终还是到了 ApplicationContext 接口,同样的,我们也可以使用绿颜色的 FileSystemXmlApplicationContext 和 AnnotationConfigApplicationContext 这两个类完成容器初始化的工作

2、FileSystemXmlApplicationContext 的构造函数需要一个 xml 配置文件在系统中的路径,其他和 ClassPathXmlApplicationContext 基本上一样

3、AnnotationConfigApplicationContext 的构造函数扫描 classpath 中相关注解的类,主流程一样

课程中我们以最经典的 classpathXml 为例。

Bean 工厂继承关系

目标:

ApplicationContext 和 BeanFactory 啥关系?

BeanFactory 和 FactoryBean 呢?

总结:

别害怕,上面的继承关系不用刻意去记住它

其实接触到的就最下面这个!

1.3 开始搭建测试项目

四步:

1、新建测试 module 项目

首先我们在 Spring 源码项目中新增一个测试项目,点击 New -> Module... 创建一个 Gradle 的 Java 项目

2、详细信息

3、设置 gradle

4、完善信息

在 build.gradle 中添加对 Spring 源码的依赖:

compile(project(':spring-context'))

spring-context 会自动将 spring-core、spring-beans、spring-aop、spring-expression 这几个基础 jar 包带进来。

接着,我们需要在项目中创建一个 bean 和配置文件(application.xml)及启动文件(Main.java)

接口如下:

package com.spring.test.service;

public interface UserService {
	public String getName();
}

实现类

package com.spring.test.impl;

import com.spring.test.service.UserService;

public class UserServiceImpl implements UserService {
	@Override
	public String getName() {
		return "Hello World";
	}
}

Main 代码如下

public class Test {
	public static void main(String[] args) {
		ApplicationContext context =
				new ClassPathXmlApplicationContext("classpath*:application.xml");

		UserService userService = context.getBean(UserService.class);
		System.out.println(userService);
		// 这句将输出: hello world
		System.out.println(userService.getName());

	}
}

配置文件 application.xml(在 resources 中)配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="userService" class="com.spring.test.impl.UserServiceImpl"/>
</beans>

运行

输出如下
com.spring.test.impl.UserServiceImpl@2aa5fe93
Hello World

1.4 工厂的构建

引言:
接下来,我们就正式讲解Spring ioC容器的源码
我们的目的:看一下ioC如何帮我们生成对象的

生命周期

1)ApplicationContext 入口

参考 IocTest.java

测试代码:spring 支持多种 bean 定义方式,为方便大家理解结构,以 xml 为案例,后面的解析流程一致

		ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:${xmlName}.xml");
		// (c)从容器中取出Bean的实例,call:AbstractApplicationContext.getBean(java.lang.Class<T>)
		//工厂模式(simple)
		UserService userService = (UserService) context.getBean("userServiceBeanId");
		// 这句将输出: hello world
		System.out.println(userService.getName());

进入到 ClassPathXmlApplicationContext 的有参构造器

org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext(java.lang.String[], boolean, org.springframework.context.ApplicationContext)

	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		//继承结构图
		//1、返回一个classloader
		//2、返回一个解析器
		super(parent);
		// 1、获取环境(系统环境、jvm环境)
		// 2、设置Placeholder占位符解析器
		// 2、将xml的路径解析完存储到数组
		setConfigLocations(configLocations);
		//默认为true
		if (refresh) {
			//核心方法(模板)
			refresh();
		}
	}

重点步骤解析(断点跟踪讲解)

super方法做了哪些事情
1、super方法:通过点查看父容器与子容器概念
2、super方法:调用到顶端,一共5层,每一层都要与讲义中的【ioC与Bean工厂类关系继承】进行对照
3、super方法:在什么地方初始化的类加载器和解析器
setConfigLocations方法做了哪些事情:
1、如何返回的系统环境和jvm环境
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值