Spring是一种用于简化复杂企业应用开发的轻量级框架,是Java程序员不能不掌握的一项技能。很多小伙伴想通过源码学习它,那么本文将展示如何一步步编译源码,为今后的深入学习做好开场。
一 什么是Spring
来看Spring官网的一段介绍:
Spring makes programming Java quicker, easier, and safer for everybody. Spring’s focus on speed, simplicity, and productivity has made it the world's most popular Java framework.
翻译:Spring使Java编程更快、更容易、更安全。Spring专注于速度、简单性和效率,使它成为世界上最受欢迎的Java框架。
Spring是由Rod Johnson 在2003年发起的,是一种用于简化复杂企业应用开发的轻量级框架,针对bean的生命周期进行管理的轻量级容器(lightweight container)。
Spring可以单独应用于构建应用程序,也可以和其他框架或组件如Mybatis、OkHttp等整合使用。
在Spring基础上,又诞生了Spring Boot、Spring Cloud、Spring Data、Spring Security等一系列基于Spring Framework的项目。
如官网介绍,Spring提供了这些核心功能: IoC、 DI(依赖注入)、AOP(面向切面编程)、数据访问、 Spring MVC、集成、测试等。
Spring功能模块
二 Spring源码编译
Spring源码基于Gradle构建,而国内程序员大多习惯了使用Maven。我们一起来看看如何构建Spring源码(基于5.3.x分支)。
github源码地址:github.com/spring-proj…
如果github下载太慢,可换成gitee。
gitee源码地址:gitee.com/mirrors/spr…
环境信息:windows 11+jdk1.8.0_202+idea 2021.3.2
- 无需提前安装gradle,使用Spring源码定义的Gradle Wrapper即可;
- 环境信息不同,编译过程中可能会遇到不同的问题。
文末有我已编译成功的源码地址。
2.1 安装Gradle Wrapper
Gradle Wrapper称为Gradle包装器,是对Gradle的一层包装,允许你在没有预先安装Gradle的情况下执行构建。好处在于,可以确保每个开发者都使用相同的Gradle版本,避免版本差异导致构建结果的不确定性。
- 在本地创建Gradle Wrapper安装目录,如“D:\javaApp\gradle-repo”
- 使用idea打开Spring源码,发现开始下载gradle-7.5.1-bin.zip,先将其取消;checkout 5.3.x分支;
- 在idea中设置Gradle
- 修改gradle/wrapper/gradle-wrapper.properties文件中distributionUrl属性(官网地址下载太慢),使用国内镜像地址: mirrors.cloud.tencent.com/gradle/grad…
- 重新点击load gradle change按钮,等Gradle Wrapper下载完成。
2.2 构建项目
2.2.1 创建init.gradle文件
Gragle Wrapper下载完成后,在安装目录下找到它(如\wrapper\dists\gradle-7.5.1-bin),在init.d目录下创建init.gradle文件(内容如下),指定Maven仓库地址(使用国内镜像,国外官网访问非常慢)。
settingsEvaluated { settings ->
settings.pluginManagement {
repositories {
maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
maven { url "https://maven.aliyun.com/repository/spring-plugin" }
gradlePluginPortal()
}
}
}
buildscript {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/public' }
}
allprojects {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/public' }
}
}
}
2.2.2 下载依赖包
重新构建,发现自动下载依赖准备编译。
如果出现依赖下载失败,往往是由于网络不佳,可多重试看看。
这个过程耗时挺长(大部分时间浪费在下载jar包上) ,我花了将近两个小时。
各模块都被加载到项目中了。
2.3 添加自定义模块
2.3.1 创建新模块
在源码中使用gradle新建模块。
在新模块build.gradle的dependencies中添加如下依赖:
compile(project(":spring-context"))
compile(project(":spring-aop"))
重新编译时报错了:“Could not find method compile() for arguments [project ':spring-context']......”。
在较新版本的Gradle(比如Gradle 5.0及以上版本)中,
compile配置已经被弃用,取而代之的是implementation或api
因此,将上面代码中的compile全都替换为implementation,重新编译。
2.3.2 创建测试类
接着创建src/main/java/com/xiake/AppConfig类、service/UserService类、MainTest类。
package com.xiakexing;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan("com.xiakexing")
@Configuration
public class AppConfig {
}
package com.xiakexing.service;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
@Component
public class UserService {
public void test() {
System.out.println("hello spring");
}
}
package com.xiakexing;
import com.xiake.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
}
}
新模块包结构如下。
2.3.3 执行main方法
jdk.jfr包不存在
执行MainTest.main方法,发现报错了:jdk.jfr.Category不存在,不能import jdk.jfr.Category。
错误信息乱码,先修改File的编码方式为UTF-8:Settings-Editor-File Encodings
由于我使用JDK8来编译,而jdk.jfr包从JDK9才添加到JDK中,因此导致报错。
有两种解决方式:
- 修改Gradle JVM和整个项目使用JDK9及以上版本;
- jdk.jfr包是JDK中的性能分析和故障排查工具,不是Spring的必备代码。因此可以将FlightRecorderStartupEvent中不能引入的类注释掉,取消继承自Event类(得注释掉FlightRecorderStartupStep类中部分代码)。
使用第二种方式,再次执行main方法,看到控制台输出如下。
Spring源码已编译成功,大功告成。
后记
以上代码已分享到Gitee仓库:gitee.com/houshifu/sp…,拉取后请使用分支5.3.x。
依赖下载过程花费了很多时间(也和网速有关)。在编译过程中可能会出现本文之外的其他问题,可在网上寻求答案,别半途而废哦。
我们已大体了解了什么是Spring,以及如何编译Spring源码。之后的文章中,我将一同走进Spring源码,了解它的底层实现。