springboot源碼分析一 ---------IDEA 引入 Spring Boot 2.1.4 源碼

下載代碼切換分支

首先到GitHubcloneSpring Boot的代碼:

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

由於Spring Boot的發佈版本代碼都在tag上,所以需要使用git tag命令查看所有的tag

git tag

然後切換到名爲v2.0.0.RELEASEtag上:

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-parentspring-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,頁面顯示:

[
	"這是測試"
]

至此,源碼編譯打包運行完畢。

總結

開源框架之所以被很多人使用,一方面是因爲解決了一些常見的痛點問題,一方面是因爲可靠和健壯,保證用開源框架開發出來的服務高可用。提高服務可靠和健壯的一方面就是單元測試,單元測試雖然繁瑣,但讓我們對自己寫的代碼和別人寫的代碼可靠性瞭然於胸。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章