Spring 下载编译

进入​​spring-framework官网​​ 点击如图所示github按钮,spring-framework的源码托管在了github上面,直接去github搜索也是可以的

Spring Framework 5.2.19源码下载和编译_ide

  • M1…M2(Milestone):里程碑版本,在版发布之前会出几个里程碑的版本。使用snapshot版本开发了一个时间,觉得最近写代码杠杠的,那么就整几个里程碑版本记录下吧
  • RC1…RC2(Release Candidates):发布候选,内部开发到一定阶段了,各个模块集成后,经过细心的测试整个开发团队觉得软件已经稳定没有问题了,可以对外发行了。
  • release:正式版本。发布候选差不多之后,那么说明整个框架到了一定的阶段了,可投入市场大面积使用了,那么发布出去,让广大用户来吃吃香吧。

这里我选择5.2.19 release版本

Spring Framework 5.2.19源码下载和编译_xml_02


然后使用git clone(需要自己下载git工具) 下来

Spring Framework 5.2.19源码下载和编译_ide_03

git clone https://github.com/spring-projects/spring-framework.git

Spring Framework 5.2.19源码下载和编译_spring_04


cd 到源码文件夹下面

cd spring-framework

Spring Framework 5.2.19源码下载和编译_ide_05

git checkout 925b078

Spring Framework 5.2.19源码下载和编译_xml_06

添加阿里云镜像仓库

找到源码文件夹下面的build.gradle文件(相当于maven的pom),编辑修改镜像仓库配置,加快下载项目依赖的速度
在279行的位置(版本不同可能不一样,也可以使用编辑器搜索功能搜索repositories)

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

Spring Framework 5.2.19源码下载和编译_ide_07

同时,我们在github上面可以看到,官网写的有教程来教我们怎么编译spring源码

​Build from Source​

Spring Framework 5.2.19源码下载和编译_xml_08


点击上方红框进入,我们选择使用IDEA来查看spring源代码

有如下图三个步骤:

(注意:第三步本博客并没有执行,没有出现错误情况,并且这个bug的​​issue​​最近一次更新也是在9年之前,估计在新版本中早已经修复了,如果有问题,就unload这个spring-aspects子项目,然后重新build spring framework)

Spring Framework 5.2.19源码下载和编译_xml_09


这里写着我们需要预编译spring-oxm,使用gradle脚本文件

gradlew脚本文件会自动帮你下载gradle(放弃,下载太慢了,还是手动下载把)

按照gradlew给我下的这个版本下载(避免出问题),版本信息在gradle/wrapper/gradle-wrapper.properties配置文件中
​​​gradle下载地址​

Spring Framework 5.2.19源码下载和编译_spring_10


gradle-5.6.4-bin.zip 文件下载到电脑本地以后,更改spring-framework源码中的gradle/wrapper/gradle-wrapper.properties配置文件

file:///为本地文件传输协议(你的gradle文件放在哪里,你就写那个路径)

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
# distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
distributionUrl=file\:///D\:/maintenance/gradle-5.6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

然后使用如下命令预编译(使用git终端)spring-oxm

./gradlew :spring-oxm:compileTestJava

Spring Framework 5.2.19源码下载和编译_xml_11


Spring Framework 5.2.19源码下载和编译_xml_12

你可能会遇到如下错误

ERROR: JAVA_HOME is set to an invalid directory

你可能需要更改一下你的系统环境变量JAVA_HOME,不能带分号,也不能带bin目录

Spring Framework 5.2.19源码下载和编译_ide_13


然后系统的path变量里面你可以追加设置这个,让电脑依然可以找到java

Spring Framework 5.2.19源码下载和编译_xml_14

IDEA 构建

使用IDEA打开spring framework项目,就会自动构建

Spring Framework 5.2.19源码下载和编译_ide_15


图中的爆红

POM relocation to an other version number is not fully supported in Gradle : xml-apis:xml-apis:2.0.2 relocated to xml-apis:xml-apis:1.0.b2.
Please update your dependency to directly use the correct version 'xml-apis:xml-apis:1.0.b2'.
Resolution will only pick dependencies of the relocated element. Artifacts and other metadata will be ignored.

解决方案:
修改引入方式,修改bulid.gradle,搜索configurations.all,添加如下内容:(不过我没管这个爆红,暂时使用没有发现问题)

可见stack overflow这篇​​Exclude transitive dependency in Gradle [duplicate]​

configurations.all {
resolutionStrategy {
force 'xml-apis:xml-apis:1.0.b2'
}
}

测试

新建一个gradle的module

Spring Framework 5.2.19源码下载和编译_ide_16


给自己的模块加依赖,里面的很多注解和应用上下ApplicationContext文我们后面都要用到

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

Spring Framework 5.2.19源码下载和编译_xml_17


编写一个简单的applicationContext获取容器用的bean,用来测试Spring源码构建编译过程是否成功

实体类User

public class User {

private String id;
private String userName;
private String age;
private String work;
private String salary;

private StringBuilder stringBuilder = new StringBuilder();

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getAge() {
return age;
}

public void setAge(String age) {
this.age = age;
}

public String getWork() {
return work;
}

public void setWork(String work) {
this.work = work;
}

public String getSalary() {
return salary;
}

public void setSalary(String salary) {
this.salary = salary;
}


@Override
public String toString() {

stringBuilder.append("User :{");
stringBuilder.append("id='" + id);
stringBuilder.append("'\\''");
stringBuilder.append(", userName='" + userName);
stringBuilder.append("'\\''");
stringBuilder.append(", age='" + age);
stringBuilder.append("'\\''");
stringBuilder.append(", work='" + work);
stringBuilder.append("'\\''");
stringBuilder.append(", salary='" + salary);
stringBuilder.append("'\\''");
stringBuilder.append("'}'");


return stringBuilder.toString();
}
}

User配置类,从这里获取User 的bean

package com.xt.spring.config;

import com.xt.spring.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

@Bean
public User user() {

User user = new User();
user.setId("1");
user.setUserName("xt");
user.setAge("24");

return user;
}
}

应用程序启动类
@ComponentScan注解也是在spring-context子项目中,指定扫描包com.xt.spring下的component,在程序中通过AnnotationConfigApplicationContext来获取由Spring自动创建的Bean。对于main函数中使用spring的场景,有两个常见的高级容器。一个是ClassPathXmlApplicationContext,基于classpath下的xml配置文件;另一种是AnnotationConfigApplicationContext,基于java配置文件。

如下是他的类图

Spring Framework 5.2.19源码下载和编译_ide_18

package com.xt.spring;

import com.xt.spring.config.UserConfig;
import com.xt.spring.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.Arrays;

@ComponentScan("com.xt.spring.**")
public class UserApplication {

public static void main(String[] args) {

System.out.println("启动...........");
long startTime = System.currentTimeMillis();
System.out.println("开始时间:" + startTime + "毫秒");
ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
User user = context.getBean(User.class);
System.out.println("信息:" + user.toString());
System.out.println(context.getBeanDefinitionCount());
Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
long endTime = System.currentTimeMillis();
System.out.println("结束时间:" + endTime + "毫秒");
System.out.println("耗时:" + (endTime - startTime) + "毫秒");
}

}

如下所示,已经获取并创建了自定义的bean了(可能你会有中文乱码问题,见下面部分内容)

Spring Framework 5.2.19源码下载和编译_xml_19

有关IDEA控制台乱码问题

修改 IntelliJ IDEA 全局编码、项目编码、属性文件编码

上方导航栏“File→Settings…”进入配置页面,在“Editor”中下滑找到“File Encodings”,分别将 Global Encoding、Project Encoding、Default encoding for properties files 都设置为 UTF-8。在重启之后运行程序检查控制台信息,如果不管用请执行下面的步骤。

Spring Framework 5.2.19源码下载和编译_spring_20

IntelliJ IDEA 中自定义虚拟机选项

上方导航栏“Help→Etit Custom VM Options…”进入自定义虚拟机选项页面。

Spring Framework 5.2.19源码下载和编译_spring_21


在 idea64.exe.vmoptions 文件尾加上-Dfile.encoding=UTF-8。在重启之后运行程序检查控制台信息,一般到了这步问题就解决了,当然如果不管用请执行下面的超级步骤。

Spring Framework 5.2.19源码下载和编译_ide_22

直接修改 IntelliJ IDEA 配置文件的编码信息

我们打开 IntelliJ IDEA 在本地的安装目录,找到下面两个文件,使用记事本打开,在最后一行添加-Dfile.encoding=UTF-8 即可。在重启之后运行程序检查控制台信息,问题解决!

Spring Framework 5.2.19源码下载和编译_spring_23


Spring Framework 5.2.19源码下载和编译_spring_24


Spring Framework 5.2.19源码下载和编译_ide_25

spring源代码各个模块作用

主要模块:

spring-core:核心模块 依赖注入IOC和DI的最基本实现
spring-beans: Bean工厂与装配
spring-context:上下文,即IOC容器
spring-context-support:对IOC的扩展,以及IOC子容器
spring-context-indexer:类管理组件和Classpath扫描
spring-expression:表达式语句

切面编程:

spring-aop:面向切面编程,CGLIB,JDKProxy
spring-aspects:集成AspectJ,Aop应用框架
spring-instrument:动态Class Loading模块

数据访问与集成:

spring-jdbc:提供JDBC主要实现模块,用于简化JDBC操作
spring-tx: spring-jdbc事务管理
spring-orm:主要集成Hibernate,jpa,jdo等
spring-oxm:将java对象映射成xml数据或将xml映射为java对象
spring-jms:发送和接受消息

web组件:

spring-web:提供了最基础的web支持,主要建立在核心容器上
spring-webmvc:实现了spring mvc的web应用
spring-websocket:主要与前端页的全双工通讯协议
spring-webflux:一个新的非阻塞函数式Reactive Web框架

报文:

spring-messaging: 4.0加入的模块,主要集成基础报文传送应用

测试:

spring-test:测试组件

集成兼容:

spring-framework-bom:解决不同模块依赖版本不同问题

References:

(写博客主要是对自己学习的归纳整理,资料大部分来源于书籍、网络资料、官方文档和自己的实践,整理的不足和错误之处,请大家评论区批评指正。同时感谢广大博主和广大作者辛苦整理出来的资源和分享的知识。)