Spring源碼分析和總結(jié)

Spring源碼分析和總結(jié)
我以下呢 就模擬一個請求 從代碼上 簡單說說 SpringMVC一個請求得流程

先來個圖

image

當一個請求(request)過來,進入DispatcherServlet中羽戒,里面有個方法叫 doDispatch方法 里面包含了核心流程

源碼如下:

image

然后往下看:(DispatcherServlet.java)

image

mapperHandler是 ** HandlerExecutionChain (處理器調(diào)用鏈) **類

HandlerExecutionChain 包含了 處理器對象 以及和處理器相關(guān)的 攔截器。 有目標方法 和 Handler

image

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****方法

image

經(jīng)過這個方法 表示沒有頁面 并且 會進入404 錯誤頁面。

二色瘩、 當請求的路徑url不存在時(沒有對應(yīng)的requestmapping注解方法)伪窖,applicationcontext.xml中存在以下注解時:

image

經(jīng)過上面的配置 則 getHandler() 不是null 因為 加上以上的配置,會調(diào)用SimpleUrlHandlerMapping 去尋找本地的靜態(tài)資源,如css js 等 但是 同樣的路徑不存在 跳轉(zhuǎn)到404頁面

三、如果存在映射居兆,繼續(xù)執(zhí)行之后的代碼:

image

執(zhí)行到上面這行:

HandlerAdapter(Handler適配器)

這個類 進行了 很多操作覆山,比如表單到實體Bean的賦值,通過Binner進行了 數(shù)據(jù)的綁定。

繼續(xù)執(zhí)行:954行

image

這里呢 底層 調(diào)用了攔截器的 PreHandle方法泥栖,如圖:

image

然后繼續(xù)執(zhí)行 到 代碼 959行(DispatcherServlet.java)

這里呢就返回了一個ModelAndView,如果所示.

image

隨后代碼繼續(xù)執(zhí)行 調(diào)用了 攔截器的 PostHandler方法 簇宽,然后調(diào)用 ProcessDispatchResult方法勋篓,如下圖:
image

繼續(xù)執(zhí)行

image

然后繼續(xù)執(zhí)行 一直到 代碼的 1027行(DisPatcherServlet.java)
image

這里就是已經(jīng)在渲染視圖了render() 方法

image

這里 通過在applicationcontext.xml中配置的視圖解析器 進行了引用 然后將頁面進行了轉(zhuǎn)發(fā),

image

個人說明:本文內(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)建:


這里寫圖片描述

目錄:

  1. 內(nèi)置Servlet Container
  2. 使用Spring Boot
  3. 安裝Spring Boot CLI
  4. 開發(fā)一個簡單的Spring Boot應(yīng)用--使用最原始的方式
    1. 創(chuàng)建一個文件夾
    2. 新建一個pom.xml文件
    3. 命令:mvn package
    4. 添加依賴
    5. 開始寫代碼
    6. 啟動項目
    7. 打包
    8. 執(zhí)行
  5. Dependency Management
    1. 繼承 spring-boot-starter-parent
    2. 不繼承 spring-boot-starter-parent
  6. Starters
  7. 自動配置
  8. Spring Beans 和 依賴注入(略)
  9. @SpringBootApplication
  10. 運行Spring Boot Application
  11. 從IDE中運行
  12. 運行fat jar(executable jar)
  13. 使用Maven Plugin
  14. Hot swapping
  15. Developer tools
  16. Property defaults
  17. 自動重啟
  18. 熱加載 LiveReload
  19. 全局設(shè)置
  20. 遠程應(yīng)用
    1. 遠程調(diào)試
  21. 生產(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恶座。   如下:

[
復(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;"><?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>

[
復(fù)制代碼

](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)容如下:

[
復(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;"><?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>

[
復(fù)制代碼

](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é)果表明遇八,當前沒有任何依賴。 
image
    OK耍休,現(xiàn)在我們添加一個Starter 模塊刃永。

[
復(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-starter-web</artifactId>
</dependency>
</dependencies></pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

    現(xiàn)在再次查看一下依賴樹。
image
    可以看出羊精,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:

[
復(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;">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>

[
復(fù)制代碼

](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 盒揉。         

[
復(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;"><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build></pre>

[
復(fù)制代碼

](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啦。方式如下:

[
復(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;"><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>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

注意萌朱,scope是 import 宴树。而且,這種情況下晶疼,不再允許在<properties>覆蓋相應(yīng)的版本酒贬。如果要使用其他版本,需要在上面的前面添加一個完整的dependency翠霍。如下:

[
復(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;"><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>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

另外锭吨,Spring Boot還提供了一個Maven Plugin:spring-boot-maven-plugin,用于將項目打包成fat jar(executable jar)寒匙。

繼承時只需要聲明一下即可使用:

[
復(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;"><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build></pre>

[
復(fù)制代碼

](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即可。

禁用特定的自動配置:

[
復(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;">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>

[
復(fù)制代碼

](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

  1. 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ā)期工具。

[
復(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>

[
復(fù)制代碼

](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下要這樣開啟:

[
復(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;"><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build></pre>

[
復(fù)制代碼

](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,那你需要進行如下操作:

  1. Select Run -> Run Configurations...
  2. Create a new Java Application "launch configuration"
  3. Browse for the my-app project
  4. Use org.springframework.boot.devtools.RemoteSpringApplication as the main class.
  5. Add https://myapp.cfapps.io to the Program arguments (or whatever your remote URL is).
image
image

代理訪問遠程的設(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/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雳窟,一起剝皮案震驚了整個濱河市砚嘴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖际长,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異兴泥,居然都是意外死亡工育,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門搓彻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來如绸,“玉大人,你說我怎么就攤上這事旭贬≌樱” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵稀轨,是天一觀的道長扼脐。 經(jīng)常有香客問我,道長奋刽,這世上最難降的妖魔是什么瓦侮? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮佣谐,結(jié)果婚禮上肚吏,老公的妹妹穿的比我還像新娘。我一直安慰自己狭魂,他們只是感情好罚攀,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雌澄,像睡著了一般斋泄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掷伙,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天是己,我揣著相機與錄音,去河邊找鬼任柜。 笑死卒废,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的宙地。 我是一名探鬼主播摔认,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宅粥!你這毒婦竟也來了参袱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抹蚀,沒想到半個月后剿牺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡环壤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年晒来,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郑现。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡湃崩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出接箫,到底是詐尸還是另有隱情攒读,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布辛友,位于F島的核電站薄扁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瞎领。R本人自食惡果不足惜泌辫,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望九默。 院中可真熱鬧震放,春花似錦、人聲如沸驼修。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乙各。三九已至墨礁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間耳峦,已是汗流浹背恩静。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蹲坷,地道東北人驶乾。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像循签,于是被迫代替她去往敵國和親级乐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容