Spring源碼分析和總結(jié)
我以下呢 就模擬一個請求 從代碼上 簡單說說 SpringMVC一個請求得流程
先來個圖
當一個請求(request)過來,進入DispatcherServlet中羽戒,里面有個方法叫 doDispatch方法 里面包含了核心流程
源碼如下:
然后往下看:(DispatcherServlet.java)
mapperHandler是 ** HandlerExecutionChain (處理器調(diào)用鏈) **類
HandlerExecutionChain 包含了 處理器對象 以及和處理器相關(guān)的 攔截器。 有目標方法 和 Handler
HandlerMapping 獲取HandlerExecutionChina對象 源碼的1120行(DispatcherServlet.java)。
這里 1115行的 Handlermapping 定義了請求到處理器之間的映射 請求找到處理器 就需要用到HandlerMapping
上面的代碼執(zhí)行完 后 又返回到 932行 繼續(xù)執(zhí)行
這里將出現(xiàn)三種 情況:
一、當請求的url路徑不存在時(沒有對應(yīng)的requestmapping注解方法)
如果發(fā)的請求的映射是空的女蜈。返回的HandlerExecutionChain mappedHandler****對象為空表示沒有對應(yīng)的映射 執(zhí)行noHandlerFound****方法
經(jīng)過這個方法 表示沒有頁面 并且 會進入404 錯誤頁面。
二色瘩、 當請求的路徑url不存在時(沒有對應(yīng)的requestmapping注解方法)伪窖,applicationcontext.xml中存在以下注解時:
經(jīng)過上面的配置 則 getHandler() 不是null 因為 加上以上的配置,會調(diào)用SimpleUrlHandlerMapping 去尋找本地的靜態(tài)資源,如css js 等 但是 同樣的路徑不存在 跳轉(zhuǎn)到404頁面
三、如果存在映射居兆,繼續(xù)執(zhí)行之后的代碼:
執(zhí)行到上面這行:
HandlerAdapter(Handler適配器)
這個類 進行了 很多操作覆山,比如表單到實體Bean的賦值,通過Binner進行了 數(shù)據(jù)的綁定。
繼續(xù)執(zhí)行:954行
這里呢 底層 調(diào)用了攔截器的 PreHandle方法泥栖,如圖:
然后繼續(xù)執(zhí)行 到 代碼 959行(DispatcherServlet.java)
這里呢就返回了一個ModelAndView,如果所示.
繼續(xù)執(zhí)行
這里就是已經(jīng)在渲染視圖了render() 方法
這里 通過在applicationcontext.xml中配置的視圖解析器 進行了引用 然后將頁面進行了轉(zhuǎn)發(fā),
個人說明:本文內(nèi)容都是從為知筆記上復(fù)制過來的魏割,樣式難免走樣譬嚣,以后再修改吧。另外钞它,本文可以看作官方文檔的選擇性的翻譯(大部分)拜银,以及個人使用經(jīng)驗及問題。
其他說明:如果對Spring Boot沒有概念遭垛,請先移步上一篇文章 Spring Boot 學(xué)習(xí)尼桶。本篇原本是為了深入了解下Spring Boot而出現(xiàn)的。
另外锯仪,Spring Boot 仍然是基于Spring的泵督,建議在趕完工之后深入學(xué)習(xí)下Spring,有興趣可以看看我的 Spring 4 官方文檔學(xué)習(xí)(十一)Web MVC 框架 卵酪。歡迎探討幌蚊,笑~
1.Spring MVC概述:
Spring MVC是Spring提供的一個強大而靈活的web框架。借助于注解溃卡,Spring MVC提供了幾乎是POJO的開發(fā)模式溢豆,使得控制器的開發(fā)和測試更加簡單。這些控制器一般不直接處理請求瘸羡,而是將其委托給Spring上下文中的其他bean漩仙,通過Spring的依賴注入功能,這些bean被注入到控制器中犹赖。
Spring MVC主要由DispatcherServlet队他、處理器映射、處理器(控制器)峻村、視圖解析器麸折、視圖組成。他的兩個核心是兩個核心:
處理器映射:選擇使用哪個控制器來處理請求
視圖解析器:選擇結(jié)果應(yīng)該如何渲染
通過以上兩點粘昨,Spring MVC保證了如何選擇控制處理請求和如何選擇視圖展現(xiàn)輸出之間的松耦合垢啼。
2.SpringMVC運行原理
(1) Http請求:客戶端請求提交到DispatcherServlet。
(2) 尋找處理器:由DispatcherServlet控制器查詢一個或多個HandlerMapping张肾,找到處理請求的Controller芭析。
(3) 調(diào)用處理器:DispatcherServlet將請求提交到Controller。
(4)(5)調(diào)用業(yè)務(wù)處理和返回結(jié)果:Controller調(diào)用業(yè)務(wù)邏輯處理后吞瞪,返回ModelAndView馁启。
(6)(7)處理視圖映射并返回模型: DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖芍秆。
(8) Http響應(yīng):視圖負責(zé)將結(jié)果顯示到客戶端惯疙。
3.SpringMVC接口解釋
(1)DispatcherServlet接口:
Spring提供的前端控制器翠勉,所有的請求都有經(jīng)過它來統(tǒng)一分發(fā)。在DispatcherServlet將請求分發(fā)給Spring Controller之前螟碎,需要借助于Spring提供的HandlerMapping定位到具體的Controller眉菱。
(2)HandlerMapping接口:
能夠完成客戶請求到Controller映射迹栓。
(3)Controller接口:
需要為并發(fā)用戶處理上述請求掉分,因此實現(xiàn)Controller接口時,必須保證線程安全并且可重用克伊。
Controller將處理用戶請求酥郭,這和Struts Action扮演的角色是一致的。一旦Controller處理完用戶請求愿吹,則返回ModelAndView對象給DispatcherServlet前端控制器不从,ModelAndView中包含了模型(Model)和視圖(View)。
從宏觀角度考慮犁跪,DispatcherServlet是整個Web應(yīng)用的控制器椿息;從微觀考慮,Controller是單個Http請求處理過程中的控制器坷衍,而ModelAndView是Http請求過程中返回的模型(Model)和視圖(View)寝优。
(4)ViewResolver接口:
Spring提供的視圖解析器(ViewResolver)在Web應(yīng)用中查找View對象,從而將相應(yīng)結(jié)果渲染給客戶枫耳。
4.DispatcherServlet:
是整個Spring MVC的核心乏矾。它負責(zé)接收HTTP請求組織協(xié)調(diào)Spring MVC的各個組成部分。其主要工作有以下三項:
(1)截獲符合特定格式的URL請求迁杨。
(2)初始化DispatcherServlet上下文對應(yīng)WebApplicationContext钻心,并將其與業(yè)務(wù)層、持久化層的WebApplicationContext建立關(guān)聯(lián)铅协。
(3)初始化Spring MVC的各個組成組件捷沸,并裝配到DispatcherServlet中。
5. SpringMVC配置
項目整體結(jié)構(gòu)如下:
(1)在web.xml文件中進行配置狐史,在配置中設(shè)置springmvc-context.xml的路徑痒给,代碼如下:
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/springmvc-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
(2)配置springmvc-context.xml文件,這一部分主要是開啟注解功能预皇、配置試圖解析器侈玄,代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd ">
<mvc:annotation-driven />
<!-- ①:對web包中的所有類進行掃描,以完成Bean創(chuàng)建和自動依賴注入的功能 -->
<context:component-scan base-package="com.zjn" />
<!-- 這兩個類用來啟動基于Spring MVC的注解功能吟温,將控制器與方法映射加入到容器中 -->
<beans:bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<beans:bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<!-- 這個類用于Spring MVC視圖解析 -->
<beans:bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/pages/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
</beans:beans>
(3)配置文件完成了序仙,下面開始寫代碼,
兩個jsp界面:
create.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Add User From</title>
</head>
<body>
<form action="save" method="post">
<fieldset>
<legend>創(chuàng)建用戶</legend>
<p>
<label>姓名:</label> <input type="text" id="name" name="name"
tabindex="1">
</p>
<p>
<label>年齡:</label> <input type="text" id="age" name="age"
tabindex="2">
</p>
<p>
<label>密碼:</label> <input type="text" id="pwd" name="pwd"
tabindex="3">
</p>
<p id="buttons">
<input id="reset" type="reset" tabindex="4" value="取消"> <input
id="submit" type="submit" tabindex="5" value="創(chuàng)建">
</p>
</fieldset>
</form>
</body>
</html>
detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div id="gloobal">
<h4>創(chuàng)建成功</h4>
<p>
<h5>詳情:</h5>
姓名:${user.name}<br /> 年齡:${user.age}<br /> 密碼:${user.pwd}<br />
</p>
</div>
</body>
</html>
UserController.java
package com.zjn.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import com.zjn.entity.User;
/**
* 用戶管理
*
* @author zjn
*/
@Controller
public class UserController {
@RequestMapping("")
public String Create(Model model) {
return "create";
}
@RequestMapping("/save")
public String Save(@ModelAttribute("form") User user, Model model) { // user:視圖層傳給控制層的表單對象鲁豪;model:控制層返回給視圖層的對象
model.addAttribute("user", user);
return "detail";
}
}
User.java
package com.zjn.entity;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
/**
* @author zjn
*/
private static final long serialVersionUID = 1L;
private Integer id; // id
private String name; // name
private String pwd; // pwd
private Integer age; // age
private Date creatTime; // creatTime
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getCreatTime() {
return creatTime;
}
public void setCreatTime(Date creatTime) {
this.creatTime = creatTime;
}
}
(4)運行結(jié)果
初始頁面:
輸入?yún)?shù):
點擊創(chuàng)建:
目錄:
- 內(nèi)置Servlet Container
- 使用Spring Boot
- 安裝Spring Boot CLI
- 開發(fā)一個簡單的Spring Boot應(yīng)用--使用最原始的方式
- Dependency Management
- Starters
- 自動配置
- Spring Beans 和 依賴注入(略)
- @SpringBootApplication
- 運行Spring Boot Application
- 從IDE中運行
- 運行fat jar(executable jar)
- 使用Maven Plugin
- Hot swapping
- Developer tools
- Property defaults
- 自動重啟
- 熱加載 LiveReload
- 全局設(shè)置
- 遠程應(yīng)用
- 生產(chǎn)打包
一潘悼、內(nèi)置Servlet Container:
Name Servlet Version Java Version <colgroup><col class="col_1"><col class="col_2"><col class="col_3"></colgroup>
Name Servlet Version Java Version Tomcat 8
|
3.1
|
Java 7+
|
|Tomcat 7
|
3.0
|
Java 6+
|
|Jetty 9.3
|
3.1
|
Java 8+
|
|Jetty 9.2
|
3.1
|
Java 7+
|
|Jetty 8
|
3.0
|
Java 6+
|
|Undertow 1.3
|
3.1
|
Java 7+
|
此外律秃,你仍然可以部署Spring Boot項目到任何兼容Servlet3.0+的容器。
二治唤、使用Spring Boot棒动。
你可以像使用標準的Java庫文件一樣使用Spring Boot。簡單的將需要的 *spring-boot-*.jar* 添加到classpath即可宾添。
Spring Boot不要求任何特殊的工具集成船惨,所以可以使用任何IDE,甚至文本編輯器缕陕。
只是粱锐,仍然建議使用build工具:Maven 或 Gradle。
Spring Boot依賴 使用 `org.springframework.boot` `groupId` 扛邑。
通常怜浅,讓你的Maven POM文件繼承 spring-boot-starter-parent,并聲明一個或多個 Starter POMs依賴即可蔬崩。Spring Boot也提供了一個可選的 Maven Plugin來創(chuàng)建可執(zhí)行的jars恶座。 如下:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- Package as an executable jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project></pre>
[](javascript:void(0); "復(fù)制代碼")
需要注意的是, spring-boot-starter-parent 是一個非常好的方法沥阳,但并不適用于所有情況跨琳。有時你需要繼承其他的POM,或者你不喜歡默認的設(shè)置沪袭。-- 辦法見后面湾宙。
三、安裝Spring Boot CLI冈绊。
這是一個命令行工具侠鳄,可以執(zhí)行Groove腳本。是執(zhí)行一個Spring Boot的最快途徑死宣。
-- 好吧伟恶,Linux下無敵,Win下還是休息吧毅该。
四博秫、開發(fā)一個簡單的Spring Boot應(yīng)用--使用最原始的方式。
務(wù)必注意:前提是maven + jdk眶掌。
1挡育、創(chuàng)建一個文件夾。SpringBootSample01
2朴爬、新建一個pom.xml文件即寒。內(nèi)容如下:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
</project></pre>
](javascript:void(0); "復(fù)制代碼")
3、上面沒有添加任何依賴,但仍然可以build母赵。命令行:mvn package逸爵。注意,是當前路徑下 //SpringBootSample01/ 凹嘲。
當然师倔,你也可以使用IDE,不過使用文本編輯器會讓我們對它更理解周蹭。
![image](http://upload-images.jianshu.io/upload_images/5776456-98a9f90240e1fa4e..png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
4趋艘、現(xiàn)在需要添加依賴 -- 其實就是把依賴的jar添加到buildpath。
由于我們已經(jīng)繼承了 spring-boot-starter-parent 谷醉,而 spring-boot-starter-parent 又提供了 dependency-management 致稀,所以我們可以忽略被選中依賴的版本冈闭。
在添加依賴之前俱尼,我們先看一下現(xiàn)在已有什么:mvn dependency:tree。該命令會打印一個當前項目的依賴樹萎攒。
結(jié)果表明遇八,當前沒有任何依賴。
OK耍休,現(xiàn)在我們添加一個Starter 模塊刃永。
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies></pre>
](javascript:void(0); "復(fù)制代碼")
現(xiàn)在再次查看一下依賴樹。
可以看出羊精,spring-boot-starter-web 包含了很多內(nèi)容斯够,spring-webmvc、spring-web喧锦、jackson读规、validation、tomcat燃少、starter束亏。
5、現(xiàn)在就可以開始寫代碼了阵具。
由于Maven默認編譯路徑為 src/main/java 下面的源碼碍遍,所以,默認設(shè)置下阳液,需要創(chuàng)建這些文件夾怕敬。
然后,編寫文件 src/main/java/Example.java:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">import org.springframework.boot.; import org.springframework.boot.autoconfigure.; import org.springframework.stereotype.; import org.springframework.web.bind.annotation.;
@RestController
@EnableAutoConfiguration public class Example {
@RequestMapping("/")
String home() { return "Hello World!";
} public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
}</pre>
](javascript:void(0); "復(fù)制代碼")
這里我們只需要關(guān)心 @EnableAutoConfiguration 即可帘皿。這個注解是讓Spring Boot*猜測 *你想怎么配置Spring东跪,但實際上,它是根據(jù)你添加到classpath中的依賴來判斷的。
注意越庇,自動配置 可以配合 Starter POMs 一起工作罩锐,但二者不是捆綁到一起的。你仍然可以將Starter POMs中的依賴單獨揀出使用卤唉,Spring Boot還是會自動配置涩惑。
6、啟動項目桑驱。由于我們使用了 spring-boot-starter-parent POM竭恬,所以可以使用 mvn spring-boot:run來啟動項目(根路徑)。
啟動之后就可以訪問了熬的,默認地址: [http://localhost:8080/](http://localhost:8080/)
7痊硕、打包。executable jars 又稱 fat jars押框,是可以直接在生產(chǎn)環(huán)境中運行的岔绸,包含所有編譯生成的class文件以及依賴包。
注意橡伞,Spring Boot的這種打包方式需要使用Spring Boot提供的 spring-boot-maven-plugin 盒揉。
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build></pre>
](javascript:void(0); "復(fù)制代碼")
注意,spring-boot-starter-parent POM中包含了 <executions> 的配置信息兑徘,綁定了 repackage goal (maven)刚盈。如果你不使用parent POM,你需要自己來聲明這個配置信息挂脑。
現(xiàn)在藕漱,可以打包了: mvn package 。
![image](http://upload-images.jianshu.io/upload_images/5776456-f320620005ea8913..png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
現(xiàn)在崭闲,你可以在/target目錄下看到 myproject-0.0.1-SNAPSHOT.jar 肋联,大約10 Mb左右《浦可以通過 jar tvf target/myproject-0.0.1-SNAPSHOT.jar 來查看其中的內(nèi)容牺蹄。
此外,在/target目錄下薄翅,還可以看到 myproject-0.0.1-SNAPSHOT.jar.original 沙兰,這是Maven打包出來的---在Spring Boot repackage 之前。
8翘魄、執(zhí)行鼎天。正常的jar執(zhí)行:java -jar target/myproject-0.0.1-SNAPSHOT.jar ,啟動信息如下:
![image](http://upload-images.jianshu.io/upload_images/5776456-627d5cdc8945d92c..png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
執(zhí)行 ctrl+c暑竟,退出斋射。
五育勺、Dependency Management
每個版本的Spring Boot都提供了一個依賴列表。這個列表包含了你可能通過Spring Boot用到的所有的Spring模塊以及第三方庫罗岖。該列表可以以BOM(Bills of Material)的形式支持Maven涧至。 --- 怎么理解BOM和Starter?什么區(qū)別桑包?南蓬?
**1、繼承 spring-boot-starter-parent **:
*spring-boot-starter-parent project *
默認是 Java 1.6哑了。 Resource filtering赘方。exec plugin、surefire弱左、Git commit ID窄陡、shade。
Resource filtering for application.properties 和 application.yml拆火,以及跳夭,profile-specific file,如application-foo.properties 或 application-foo.yml榜掌。
-- 注意Maven filtering使用 *@..@* 占位符优妙,你可以在Maven property中覆蓋:resource.delimiter。
如果不想使用Spring Boot中的默認版本憎账,可以在<properties>覆蓋相應(yīng)的版本,如卡辰,想使用不同版本的Spring Data胞皱,具體如下:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><properties>
<spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version>
</properties></pre>
**想使用不同版本的JDK**:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">
<java.version>1.8</java.version></pre>
2、不繼承 spring-boot-starter-parent :
這種情況下九妈,仍然可以使用dependency management反砌,但不能使用plugin management啦。方式如下:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.4.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement></pre>
](javascript:void(0); "復(fù)制代碼")
注意萌朱,scope是 import 宴树。而且,這種情況下晶疼,不再允許在<properties>覆蓋相應(yīng)的版本酒贬。如果要使用其他版本,需要在上面的前面添加一個完整的dependency翠霍。如下:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>Fowler-SR2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.4.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement></pre>
](javascript:void(0); "復(fù)制代碼")
另外锭吨,Spring Boot還提供了一個Maven Plugin:spring-boot-maven-plugin,用于將項目打包成fat jar(executable jar)寒匙。
繼承時只需要聲明一下即可使用:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build></pre>
](javascript:void(0); "復(fù)制代碼")
六零如、Starters
可以創(chuàng)建自己的Starter,但名字格式不能是 spring-boot-starter-*,而是 *-spring-boot-starter考蕾。類似Maven插件的規(guī)則祸憋。
七、自動配置
@Import 和 @ComponentScan 類似肖卧;
@EnableAutoConfiguration 和 @SpringBootApplication 類似夺衍;---注意,只能使用一次喜命,建議用在primary @Configuration class上沟沙。
注意,自動配置永遠是第二位的壁榕,一旦你配置自己的東西矛紫,那自動配置的就會被覆蓋。
查看自動配置都配置了什么牌里,以及為什么颊咬,啟動應(yīng)用的時候加上 --debug即可。
禁用特定的自動配置:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">import org.springframework.boot.autoconfigure.; import org.springframework.boot.autoconfigure.jdbc.; import org.springframework.context.annotation.*;
@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) public class MyConfiguration {
}</pre>
](javascript:void(0); "復(fù)制代碼")
如果class不在classpath中牡辽,可以使用 excludeName喳篇,然后使用全路徑即可。
八态辛、Spring Beans 和 依賴注入麸澜。
九、@SpringBootApplication
@SpringBootApplication 等同于默認的屬性的 @Configuration
, @EnableAutoConfiguration
and @ComponentScan
奏黑。
-- 注意炊邦,@ComponentScan 不能憑空使用。
十熟史、運行Spring Boot Application
1馁害、從IDE中運行
需要導(dǎo)入現(xiàn)有Maven項目。
如果不小心運行了兩次蹂匹,出現(xiàn)端口占用問題碘菜,STS(Spring Tools Suite)使用Relaunch即可。
2限寞、運行fat jar(executable jar)
java -jar target/xxxx.jar 注意忍啸,是在項目路徑下執(zhí)行。
開啟遠程調(diào)試支持:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -jar target/myproject-0.0.1-SNAPSHOT.jar</pre>
3昆烁、使用Maven Plugin
mvn spring-boot:run
4豌鸡、Hot swapping 熱部署蛾默?遏佣?? 好像不是传泊,是熱加載。
因為Spring Boot應(yīng)用都是簡單的Java應(yīng)用鸭巴,所以JVM Hot-swapping可以直接使用眷细。但是,JVM Hot-swapping對于能夠替換的字節(jié)碼有些限制鹃祖,所以建議使用JRebel或者Spring Loaded溪椎??
spring-boot-devtools 模塊同樣包含了快速重啟應(yīng)用的支持恬口。
另外校读,貌似JVM Hot-swapping 只能在debug期間修改方法體?祖能?
十一歉秫、Developer tools
Spring Boot包含一組附加的開發(fā)期工具。
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies></pre>
](javascript:void(0); "復(fù)制代碼")
注意养铸,生產(chǎn)環(huán)境下(java -jar或者通過特定的類加載器啟動)雁芙,這些開發(fā)工具自動被禁止。
上面的 <optional>****true****</optional> 是一個最佳實踐钞螟,可以有效阻止用于其他模塊兔甘。
如果想確保生產(chǎn)Build中不包含devtools,可以使用excludeDevtools build property鳞滨。
1洞焙、Property defaults
一些Spring Boot支持的庫使用了cache增進性能。但是cache太援,在開發(fā)過程中可能會是一個阻礙闽晦。例如你無法立即更新一個模板(thymeleaf的)。
cache設(shè)置通常在 application.properties 中提岔。但是,比起手動設(shè)置這些笋敞,spring-boot-devtools模塊會自動應(yīng)用這些開發(fā)期的設(shè)置碱蒙。
2、自動重啟
使用spring-boot-devtools模塊的應(yīng)用夯巷,當classpath中的文件有改變時赛惩,會自動重啟! -- 就是說趁餐,默認會監(jiān)視classpath入口喷兼。
靜態(tài)資源和視圖模板不需要重啟!
注意后雷,不同的IDE有不同的表現(xiàn)季惯,例如Eclipse中只要改變了文件并保存吠各,那就會導(dǎo)致classpath中的內(nèi)容改變。而Intellij IDEA則需要 Build #Make Project勉抓。
可以通過build plugin啟動應(yīng)用贾漏,只要開啟了forking支持,因為Devtools需要一個隔離的classloader才能運行正常藕筋。Maven下要這樣開啟:
[](javascript:void(0); "復(fù)制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build></pre>
](javascript:void(0); "復(fù)制代碼")
注意:在使用LiveReload(熱加載)時纵散,自動重啟仍然可以正常工作。如果你使用了JRebel隐圾,自動重啟會被禁用以支持動態(tài)類加載伍掀。此時,devtools其他方面仍然可以使用暇藏。
注意:DevTools在重啟過程中依賴應(yīng)用上下文的shutdown hook來關(guān)掉它(應(yīng)用)蜜笤。所以如果禁用了shutdown hook,它就無法正常工作了:SpringApplication.setRegisterShutdownHook(false)叨咖。
Spring Boot使用的重啟技術(shù)瘩例,實際上是使用了兩個類加載器:不變的base類加載器、可變的restart類加載器甸各。前者加載第三方j(luò)ar之類的垛贤。后者加載項目代碼。重啟的時候趣倾,只是丟棄可變的restart類加載器聘惦,然后重新創(chuàng)建一個,所以速度比較快儒恋。
如果你覺得這樣仍然不夠快善绎,或者遇到了類加載器問題,那你可以考慮JRebel之類的重加載技術(shù)诫尽。(重寫了類禀酱??)
Spring Loaded項目提供了另一個選擇牧嫉,但是支持的框架不夠多剂跟,且沒有商業(yè)支持。
一些特定的資源改變時沒有必要引起重啟酣藻。有一些不會引起重啟曹洽,但是會重加載。如果你想自定義的設(shè)置一下辽剧,可以使用 spring.devtools.restart.exclude 屬性送淆。如下:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">spring.devtools.restart.exclude=static/,public/</pre>
如果想在默認的設(shè)置之外再添加新的排除選項,可以使用 spring.devtools.restart.additional-exclude 屬性怕轿。
如果想在修改classpath之外的文件時也讓應(yīng)用重啟偷崩,可以使用 spring.devtools.restart.additional-paths 屬性辟拷。還可以配合上面提到的 spring.devtools.restart.exclude 屬性,來控制是重啟還是重加載环凿。
如果不想使用自動重啟功能梧兼,可以使用 spring.devtools.restart.enabled 屬性。多數(shù)情況下智听,可以在 application.properties 中設(shè)置羽杰,這樣仍然會創(chuàng)建一個restart類加載器,但不再監(jiān)視改變到推。
如果想完全禁止自動重啟考赛,需要在調(diào)用 SpringApplication.run(..) 之前設(shè)置一個System屬性。如下:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);
}</pre>
如果你的IDE會隨改隨編譯莉测,你可能會傾向于只在特定時刻引發(fā)重啟(否則會很煩人颜骤,而且性能下降)。這時捣卤,你可以使用“trigger file”忍抽,就是一個特定的文件,只有修改這個文件時才會觸發(fā)重啟董朝。使用 spring.devtools.restart.trigger-file 屬性即可鸠项。(還可以設(shè)置為全局屬性,這樣所有的項目都可以使用了子姜!見十八祟绊。)
自定義restart類加載器。
如果有一個多模塊項目哥捕,只有部分導(dǎo)入到你的IDE中牧抽,你可能需要自定義一下。首先創(chuàng)建一個文件:META-INF/spring-devtools.properties遥赚。該文件中扬舒,可以有以前綴 restart.exclude. 和 restart.include. 開頭的屬性。前者會被放入base類加載器凫佛,后者則被放入restart類加載器呼巴。
該屬性的value,是正則表達式御蒲。例如:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">restart.include.companycommonlibs=/mycorp-common-[\w-]+.jar
restart.include.projectcommon=/mycorp-myproj-[\w-]+.jar</pre>
注意,key只要是前綴 restart.exclude. 和 restart.include. 開頭即可诊赊,后綴任意厚满。
已知限制:
自動重啟,在使用 ObjectInputStream 反序列化時碧磅,會出問題碘箍。如果你想使用反序列化遵馆,應(yīng)該使用Spring的 ConfigurableObjectInputStream 配合 Thread.currentThread().getContextClassLoader() 使用。
可惜的是丰榴,一些第三方j(luò)ars中沒有考慮到這個問題货邓,無解。
3四濒、熱加載 LiveReload
spring-boot-devtools 模塊內(nèi)置了一個 LiveReload Server换况,可以保證在改變資源時 瀏覽的刷新。LiveReload的瀏覽器擴展盗蟆,免費支持Chrome戈二、Firefox、Safari喳资。
如果想禁用:spring.devtools.livereload.enabled=false 觉吭。
注意:只能運行一個LiveReload Server。如果同時開啟多個項目仆邓,那只有第一個鲜滩。
4、全局設(shè)置(前面有提到)
$HOME 文件夾下添加一個文件 .spring-boot-devtools.properties 节值,該文件中的內(nèi)容會被作用于所有的Spring Boot項目徙硅。例如設(shè)置 觸發(fā)文件:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">spring.devtools.reload.trigger-file=.reloadtrigger</pre>
5、遠程應(yīng)用
Spring Boot 的developer tools也可以在遠程使用(應(yīng)該是使用一部分)察署。需要開啟支持闷游。例如:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">spring.devtools.remote.secret=mysecret</pre>
問題:值是什么意思?
注意:不要在生產(chǎn)環(huán)境下開啟L簟脐往!
遠程devtools支持是成對出現(xiàn)的。服務(wù)器端+客戶端扳埂。當設(shè)置了上面的屬性時业簿,服務(wù)器端會自動開啟。
運行遠程客戶端應(yīng)用:
運行 org.springframework.boot.devtools.RemoteSpringApplication 阳懂,需要使用和遠程項目相同的classpath梅尤!
傳遞給應(yīng)用的non-option參數(shù)應(yīng)該是你要連接到的URL。(問題岩调,什么是non-option參數(shù)巷燥?)
例如,你在使用Eclipse或者STS号枕,有一個項目 my-app 缰揪,部署到了Cloud Foundry,那你需要進行如下操作:
Select Run -> Run Configurations...
Create a new Java Application "launch configuration"
Browse for the my-app project
Use org.springframework.boot.devtools.RemoteSpringApplication as the main class.
Add https://myapp.cfapps.io to the Program arguments (or whatever your remote URL is).
代理訪問遠程的設(shè)置方法(略)葱淳。p47(60/346)
遠程方式下钝腺,客戶端的任何更新都會被push到服務(wù)器端抛姑,并按設(shè)置觸發(fā)restart。比較快艳狐。
5.1定硝、遠程調(diào)試
并不總是能開啟Java遠程調(diào)試功能。(直接翻譯的毫目,略拗口蔬啡。其實就是有時候能開啟,有時候不能)
為了改進這些限制蒜茴,devtools支持Http協(xié)議的遠程調(diào)試通道星爪。遠程客戶端提供了一個本地服務(wù)器(默認8000端口,可修改)粉私,用于綁定遠程調(diào)試器顽腾。當一個連接被創(chuàng)建時,debug信息就會通過HTTP發(fā)送到遠程應(yīng)用诺核。
修改默認端口: spring.devtools.remote.debug.local-port 抄肖。
但是,首先窖杀,你需要確認遠程應(yīng)用以遠程調(diào)試方式啟動漓摩。通常,配置JAVA_OPTS即可達到目的入客。例如管毙,在Cloud Foundry上,你可以在 manifest.yml 中添加如下信息:
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">---
env:
JAVA_OPTS: "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n"</pre>
注意桌硫,通過網(wǎng)絡(luò)進行遠程調(diào)試夭咬,可能很慢,所以你需要增加超時時間铆隘。Eclipse中:Java -> Debug -> Debugger timeout (ms)卓舵,設(shè)成60000很不錯。
十二膀钠、生產(chǎn)打包
Executable jars可以直接在生產(chǎn)環(huán)境下使用掏湾。
其他的生產(chǎn)就緒功能,例如監(jiān)控等肿嘲,可以考慮 spring-boot-actuator 融击。后面會有介紹。
官方文檔: http://docs.spring.io/spring-boot/docs/1.4.0.RELEASE/reference/htmlsingle/