# Spring源码编译及阅读源码入门

# 我为什么要去读源码

首先说明我并不是什么大佬,普普通通小开发一枚,那为什么我要去读源码呢?

其实不管是 Spring 还是 JDK 的源码,如果我们想要称为更高阶的开发者,阅读源码是必经阶段,第一可以提高自己的代码能力,因为个人觉得写好代码的最好方式就是看别人怎么写代码并学习,第二是提升自己后找到更好的工作,如果我们去看大厂的招聘要求基本都是要精通 Spring,实际上我们可能没办法做到精通,但至少可以确定自己的方向。

另外就是 Spring 在企业开发中基本上已经撑起了半边天,正如Spring 官网所说Spring makes Javasimple

# 我适合去读源码吗

对于个问题,我觉得我应该有发言权,有看过我文章的同学应该都知道,我之前更过一部分JDK相关源码的文章,主要是 JUC (opens new window) 相关的,而且我是断层更新的,主要原因就是因为我看了 2 遍,第 1 遍去看的时候是处于离职状态,为了找工作所以去看的,但处于一个离职的场景和刚毕业 1 年,又是非科班,看起来相当吃力,本身自己就没写过多少代码,所以看别人的就更看不懂了。因此,对我来说,我可以尝试去看源码,是因为我给自己定义了以下的要求,并且可以达到:

  1. 工作经验

    我是 19 年毕业,至今 2 年半的工作经验,所涉及的项目都是基于 Spring 和 SpringBoot 开发,所以你应该知道什么是 Spring 并且有使用过相关的组件。

  2. 代码量

    对于学生而言,实际代码量可能相对较少,因此我并不觉得需要在学生阶段来阅读 Spring 源码,因为他们可以通过校招进入自己向往的企业,我觉得现在的大学生都非常厉害,所以你能去读源码并且也是有时间的,真的是非常好的一件事。对比我那个时候,我还在网吧玩游戏呢。那么对于已经毕业的怎么提高代码量呢?

    第一是公司业务,不要瞧不起CRUD,无论简单还是复杂的业务最后都是CRUD,关键点在于怎么写好CRUD。

    第二是开源项目,个人非常喜欢逛 github 和码云,一般碰到感兴趣的项目会拉下来参考学习,看看别人怎么设计代码的结构以及如何优雅的写出代码。

  3. 心态

    心态是非常重要的,如果你连心都静不下来,看几眼就觉得好难,觉得看不下去了,这样白白浪费时间。比如我刚工作一年的时候,满心想的就是到点下班,晚上搞几把游戏等等之类的。当然并不是说要把全部精力投入进来,就连我现在放假还是照样玩游戏,它不香吗,哈哈哈。我的意思如果你能静下来,你还得有目标,并不是单纯看看就完事。

  4. 目标

    我不知道你们有没有听过这样一句话:但凡家里有钱,干啥都不干开发。确实,我觉得没毛病,但实际也不缺乏真感兴趣的人,对我而言,我想深入的学习提高自己,进入自己理想的公司,证明自己,就这么简单。

# 通过什么方式去读源码

最好的方式就是跟着官方文档,但官方文档都是英文,懂的都懂,所以一般可能都是通过去看书或者博客或者培训课程,我没办法说那种方式好,因为对于上班族而言,本来上班就够累还要去看书,动都不想动的。

我的方式是看视频,看别人的讲解来吸收并笔记下来,同时通过百度查找自己需要了解的问题。因为你说你去看源码,你根本不知道如何下手,从哪里看?这都是问题,所以需要去找适合自己的方式。

# Spring 源码编译

说了这么多,首先我们先把 Spring 源码拉下来再说,这里选择的版本为v5.2.8.RELEASE (opens new window),或点击下载 (opens new window)(提取码:3022)。

如果你完全不想去手动编译,或者按照下面的流程有问题又无法解决,这里提供已经编译好的源码,直接导入IDEA即可。

码云:https://gitee.com/javatv/spring-framework-5.2.8.-release.git

image-20211021110428722

# 安装gradle

由于Spring是基于gradle打包的,所以我们需要配置gradle,点击下载 (opens new window)(提取码:336c)。

解压后配置环境变量:

GRADLE_HOME:磁盘目录\gradle-6.0.1 Path:%GRADLE_HOME%\bin

然后通过dos命令执行:gradle -v

image-20211021115036223

# 修改settings.gradle文件

image-20211021111956035

添加如下代码:

maven { url 'https://maven.aliyun.com/repository/public' }
1

image-20211021111834354

# 修改gradle.properties文件

替换为如下配置:

version=5.2.8.RELEASE
org.gradle.jvmargs=-Xmx2048M
org.gradle.caching=true
org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.daemon=true
1
2
3
4
5
6

# 修改build.gradle文件

第 279 行添加如下代码:

maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter'}
1
2

image-20211021112527762

# 编译spring-oxm模块

通过命令编译:

gradlew :spring-oxm:compileTestJava
1

如果出现下面这种情况,需要在 build.gradle 文件下注释掉下面这行代码:

image-20211021115910788

注释代码:

image-20211021120204400

# IDEA导入Spring源码

1、选择项目文件

image-20211021134920689

2、导入

image-20211021134953539

image-20211021135041415

3、导入后等待编译

image-20211021142554531

# 测试

写个测试类测试模块是否导入正确,在spring-context包的test包下创建两个测试类。如下:

TestConfig类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TestConfig {
	
	@Bean
	public String isSuccess() {
		return "Hello Spring success";
	}
}
1
2
3
4
5
6
7
8
9
10
11

TestMain类

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestMain {

	public static void main(String[] args) {
		ApplicationContext acx = new AnnotationConfigApplicationContext(TestConfig.class);
		Object name = acx.getBean("isSuccess");
		System.out.println(name);
	}
}
1
2
3
4
5
6
7
8
9
10
11

然后就可以断点运行测试了:

image-20211021155733622

如果上面方式有问题,可以看这篇文章:

Spring5.x源码环境搭建-读源码必备 (opens new window)

# Spring整体架构

Spring框架是一种分层架构,它包含了一系列的功能,大概由20种模块组成。 这些模块分为核心容器(Core Container),数据访问/集成(Data Access/Integration), Web,AOP,工具(Instrumentation), 消息(Messaging), 测试用例(Test)。 image-20211021161101862

# 模块介绍

按照 Spring 的源码结构依次介绍

image-20211021142554531

1、spring-aop

面向切面编程时使用。Spring通过"横切"的方式将贯穿于多业务中的公共功能独立抽取出来,形成单独的切面,并指定切面的具体动作,在需要使用该功能时,动态地将该功能切入到需要的地方。

2、spring-aspects

用来实现AspectJ框架的集成。而AspectJ是一个通过对java扩展出之后的框架,框架里面定义了AOP的语法,通过特殊的编译器完成编译期间的代码织入,最后生成增强之后的Class文件。

3、spring-beans

完成Spring框架的基本功能,里面定义了大量和Bean有关的接口,类及注解。例如:bean定义的顶层接口BeanDefinition、bean装配相关的注解Autowired/Qualifier/Value、用来创建bean的工厂接口BeanFactory及一些具体的工厂方法等。

4、spring-context

用来实现Spring上下文功能,及Spring的IOC,例如初始化Spring容器时所使用的ApplicationContext接口及常用的抽象实现类AnnotationConfigApplicatoinContext或者ClasspathXmlApplicationContext等。

5、spring-context-indexer

用来创建Spring应用启动时候选组件的索引,以提高应用的启动速度。通常情况下,应用启动的时候会去扫描类路径下的所有组件,但是如果组件特别多,会导致应用启动特别缓慢。该模块可以在应用的编译器对应用的类路径下的组件创建索引,在启动的时候通过索引去加载和初始化组件,可以大大提升应用启动的速度。

6、spring-context-support

用来提供Spring上下文的一些扩展模块,例如实现邮件服务、视图解析、缓存(定义了对下面几种缓存的支持:caffeine,ehcache,jcache)、定时任务调度等。

7、spring-core

Spring的核心功能实现,例如:控制反转(IOC)、依赖注入(DI)、asm以及cglib的实现。

8、spring-expression

提供Spring表达式语言的支持,SPEL。

9、spring-framework-bom

通过该模块,可以解决Spring中的模块与其他框架整合时产生jar包版本的冲突,默认为空实现。

10、spring-instrument

实现Spring对服务器的代理接口功能实现,实现的是类级别或者ClassLoader级别的代理功能。

11、spring-jcl

通过适配器设计模式实现的一个用来统一管理日志的框架,对外体统统一的接口,采用"适配器类"将日志的操作全部委托给具体的日志框架,提供了对多种日志框架的支持。

12、spring-jdbc

Spring对JDBC(Java Data Base Connector)功能的支持,里面定义了用于操作数据的多种API,常用的即:JdbcTemplate,通过模板设计模式将数据库的操作和具体业务分离,降低了数据库操作和业务功能的耦合。

13、spring-jms

对Java消息服务的支持,对JDK中的JMS API进行了简单的封装。

14、spring-messaging

实现基于消息来构建服务的功能。

15、spring-orm

提供了一些整合第三方ORM框架的抽象接口,用来支持与第三方ORM框架进行整合,例如:MyBatis,Hibernate,Spring JPA等。

16、spring-oxm

Spring用来对对象和xml(Object/xml)映射的支持,完成xml和object对象的相互转换。

17、spring-test

Spring对Junit测试框架的简单封装,用来快速构建应用的单元测试功能及Mock测试。

18、spring-tx

Spring对一些数据访问框架提供的声明式事务或者编程式事务(通过配置文件进行事务的声明)的支持。例如:Hibernate,MyBatis,JPA等。

19、spring-web

用来支持Web系统的功能。例如:文件上传,与JSF的集成,过滤器Filter的支持等。

20、spring-webflux

Spring5中新增的一个通过响应式编程来实现web功能的框架。内部支持了reactive和非阻塞式的功能,例如可以通过tcp的长连接来实现数据传输。webmvc的升级版,webmvc是基于servlet的,而webflux是基于reactive的。

21、spring-webmvc

用来支持SpringMVC的功能,包括了和SpringMVC框架相关的所有类或者接口,例如常用的DispatcherServlet、ModelAndView、HandlerAdaptor等。另外提供了支持国际化、标签、主题、FreeMarker、Velocity、XSLT的相关类。注意:如果使用了其他类似于smart-framework的独立MVC框架,则不需要使用该模块中的任何类。

22、spring-websocket

Spring对websocket的简单封装,提供了及时通信的功能,常用于一些即时通讯功能的开发,例如:聊天室。

# 模块间依赖关系

SpringCore模块

spring-context:
   -spring-core
   -spring-beans
   -spring-aop
   -spring-expression
   -spring-instrument[optional]
1
2
3
4
5
6

SpringAOP模块

spring-aop:
   -spring-core
   -spring-beans
   -aspectjweaver[optional]
1
2
3
4

SpringJDBC模块

spring-jdbc:
   -spring-core
   -spring-beans
   -spring-tx
   -spring-context[optional]

spring-tx:
   -spring-core
   -spring-beans
   -spring-aop[optional]
   -spring-context[optional]

spring-orm:
   -spring-core
   -spring-beans
   -spring-jdbc
   -spring-tx
   -spring-aop[optional]
   -spring-context[optional]
   -spring-web[optional]

spring-oxm:
   -spring-core
   -spring-beans

spring-jms:
   -spring-core
   -spring-beans
   -spring-messaging
   -spring-tx
   -spring-aop[optional]
   -spring-context[optional]
   -spring-oxm[optional]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

SpringWeb


spring-web:
   -spring-core
   -spring-beans
   -spring-aop[optional]
   -spring-context[optional]
   -spring-oxm[optional]

spring-webmvc:
   -spring-core
   -spring-beans
   -spring-web
   -spring-expression
   -spring-context
   -spring-aop
   -spring-context-support[optional]
   -spring-oxm[optional]

spring-websocket:
   -spring-core
   -spring-web
   -spring-context
   -spring-webmvc[optional]
   -spring-messaging[optional]

spring-messaging:
   -spring-core
   -spring-beans
   -spring-context[optional]
   -spring-oxm[optional]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 参考

Spring的20几个模块分别都是干嘛用的? (opens new window)