下载代码切换分支
首先到GitHub
上clone
下Spring Boot
的代码:
git clone https://github.com/spring-projects/spring-boot.git
由于Spring Boot
的发布版本代码都在tag
上,所以需要使用git tag
命令查看所有的tag
:
git tag
然后切换到名为v2.0.0.RELEASE
的tag
上:
git checkout -b v2.0.0.RELEASE v2.0.0.RELEASE
这样,代码就被保存到本地分支v2.0.0.RELEASE
上了。
源码编译
Spring Boot
官方建议使用./mvnw clean install
或者标准的mvn clean install
命令来编译源代码,如果要使用标准的mvn
命令的话,Maven
的版本要求在3.5.0
或以上。导入IDEA
源码视图如下:
接着切换到spring-boot
根目录下,执行如下命令,我这里使用的Maven
版本是3.5.4:
mvn -Dmaven.test.skip=true clean install
以上命令对Spring Boot
源码打包并安装到本地maven
仓库,在打包过程中会忽略测试,因为运行单元测试时间特别长,下载源码的目的是学习和分析Spring Boot
的原理,而并不是做定制开发,因此一些不影响学习的单元测试可以忽略掉,可以不关注单测的结果。命令执行结果如下:
打包失败主要是因为失败单元测试引起的,这些单元测试会影响最终编译打包结果:
org.springframework.boot.gradle.plugin.OnlyDependencyManagementIntegrationTests > dependencyManagementCanBeConfiguredUsingCoordinatesConstant [Gradle default] FAILED
java.lang.RuntimeException at OnlyDependencyManagementIntegrationTests.java:42
Caused by: org.gradle.testkit.runner.UnexpectedBuildFailure at OnlyDependencyManagementIntegrationTests.java:42
org.springframework.boot.gradle.plugin.OnlyDependencyManagementIntegrationTests > dependencyManagementCanBeConfiguredUsingCoordinatesConstant [Gradle 4.1] FAILED
java.lang.RuntimeException at OnlyDependencyManagementIntegrationTests.java:42
Caused by: org.gradle.testkit.runner.UnexpectedBuildFailure at OnlyDependencyManagementIntegrationTests.java:42
org.springframework.boot.gradle.plugin.OnlyDependencyManagementIntegrationTests > dependencyManagementCanBeConfiguredUsingCoordinatesConstant [Gradle 4.2] FAILED
java.lang.RuntimeException at OnlyDependencyManagementIntegrationTests.java:42
Caused by: org.gradle.testkit.runner.UnexpectedBuildFailure at OnlyDependencyManagementIntegrationTests.java:42
org.springframework.boot.gradle.plugin.OnlyDependencyManagementIntegrationTests > dependencyManagementCanBeConfiguredUsingCoordinatesConstant [Gradle 4.3] FAILED
java.lang.RuntimeException at OnlyDependencyManagementIntegrationTests.java:42
Caused by: org.gradle.testkit.runner.UnexpectedBuildFailure at OnlyDependencyManagementIntegrationTests.java:42
org.springframework.boot.gradle.plugin.OnlyDependencyManagementIntegrationTests > dependencyManagementCanBeConfiguredUsingCoordinatesConstant [Gradle 4.4.1] FAILED
java.lang.RuntimeException at OnlyDependencyManagementIntegrationTests.java:42
Caused by: org.gradle.testkit.runner.UnexpectedBuildFailure at OnlyDependencyManagementIntegrationTests.java:42
org.springframework.boot.gradle.plugin.OnlyDependencyManagementIntegrationTests > dependencyManagementCanBeConfiguredUsingCoordinatesConstant [Gradle 4.5] FAILED
java.lang.RuntimeException at OnlyDependencyManagementIntegrationTests.java:42
Caused by: org.gradle.testkit.runner.UnexpectedBuildFailure at OnlyDependencyManagementIntegrationTests.java:42
这些失败的单测属于spring-boot-project/spring-boot-tools
下的spring-boot-gradle-plugin
项目,一个比较暴力的解决办法是直接删掉这个项目下的src/test/java
,不运行这个项目的单测,因为暂时也用不到它。删除后再执行:
mvn -Dmaven.test.failure.ignore=true -Dmaven.test.skip=true clean install
以上命令中的-Dmaven.test.failure.ignore=true
会使Maven
忽略掉失败的单元测试,等待命令执行5-10分钟,显示执行成功:
接下来就可以创建测试项目进行源码调试了。
测试
打包成功之后,在spring-boot/spring-boot-project
目录下创建一个Spring Boot
项目测试一下自己编译的源码是否可以正常运行,在spring-boot-project
上点击New->Module
为它创建一个名为spring-boot-example
的子module
,接着按照标准Spring Boot
服务的顺序来创建Application
、配置文件application.yml
和相应的controller
,创建完成后,视图如下:
代码依次如下:
1、Application类:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args); }
}
2、WebController类:
@Controller
@RequestMapping(value = "/web", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public class WebController {
@GetMapping(value = "/test")
public List test() {
List list = new ArrayList();
list.add("这是测试");
return list;
}
}
3、application.yml:
server:
port: 6011
spring:
application:
name: spring-boot-example
4、pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>${revision}</version>
<relativePath>../spring-boot-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-example</artifactId>
<packaging>jar</packaging>
<name>spring-boot-example Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<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>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- Compile -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>spring-boot-example</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable> <!-- Add -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
</project>
接下来,还需要将spring-boot-project/spring-boot-parent
和spring-boot-project/spring-boot-starters
两个项目的pom.xml
里的maven-checkstyle-plugin
信息注释掉,才可以运行的测试项目,因为这个插件会对代码进行检查,检查失败的话,服务运行不起来。
最后,直接运行Application
类,输出运行成功日志:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::
2018-09-04 11:07:37.046 INFO 4576 --- [ main] o.s.boot.example.Application : Starting Application on Armons-MacBook-Pro.local with PID 4576 (/Users/pengwang/Documents/workspace-oxygen/data/spring-boot/spring-boot-project/spring-boot-example/target/classes started by wangpeng in /Users/pengwang/Documents/workspace-oxygen/data/spring-boot)
2018-09-04 11:07:37.079 INFO 4576 --- [ main] o.s.boot.example.Application : No active profile set, falling back to default profiles: default
2018-09-04 11:07:37.248 INFO 4576 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@75c072cb: startup date [Tue Sep 04 11:07:37 CST 2018]; root of context hierarchy
2018-09-04 11:07:40.565 INFO 4576 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 6011 (http)
2018-09-04 11:07:40.619 INFO 4576 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2018-09-04 11:07:40.619 INFO 4576 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.28
2018-09-04 11:07:40.641 INFO 4576 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/pengwang/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2018-09-04 11:07:40.837 INFO 4576 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-09-04 11:07:40.838 INFO 4576 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3594 ms
2018-09-04 11:07:41.179 INFO 4576 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]
2018-09-04 11:07:41.183 INFO 4576 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-09-04 11:07:41.184 INFO 4576 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-09-04 11:07:41.184 INFO 4576 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-09-04 11:07:41.184 INFO 4576 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2018-09-04 11:07:41.617 INFO 4576 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@75c072cb: startup date [Tue Sep 04 11:07:37 CST 2018]; root of context hierarchy
2018-09-04 11:07:41.731 INFO 4576 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/web/test],methods=[GET],produces=[application/json;charset=UTF-8]}" onto public java.util.List org.springframework.boot.example.WebController.test()
2018-09-04 11:07:41.738 INFO 4576 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-09-04 11:07:41.739 INFO 4576 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-09-04 11:07:41.791 INFO 4576 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-04 11:07:41.792 INFO 4576 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-04 11:07:41.849 INFO 4576 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-04 11:07:42.101 INFO 4576 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-09-04 11:07:42.175 INFO 4576 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 6011 (http) with context path ''
2018-09-04 11:07:42.180 INFO 4576 --- [ main] o.s.boot.example.Application : Started Application in 6.077 seconds (JVM running for 6.955)
打开浏览器访问http://localhost:6011/web/test,页面显示:
[
"这是测试"
]
至此,源码编译打包运行完毕。
总结
开源框架之所以被很多人使用,一方面是因为解决了一些常见的痛点问题,一方面是因为可靠和健壮,保证用开源框架开发出来的服务高可用。提高服务可靠和健壮的一方面就是单元测试,单元测试虽然繁琐,但让我们对自己写的代码和别人写的代码可靠性了然于胸。