Spring Boot 官網文檔簡單翻譯 Part III

Part III. Using Spring Boot

文檔說明:

  • 文檔對應的版本為 2.1.0.M3
  • 這不是文檔的完整中文翻譯,也有可能跟原文文字不一一對應,只是我閱讀文檔時候做的簡單筆記
  • 如果對應的章節沒有任何中文,有可能是文檔內容比較少,建議直接看原文,或者是我不感興趣的部分
  • 目錄標題沒有做翻譯,首先標題一般一眼就能看懂什么意思,不做翻譯還能保證原文意思,其次也方便對應到原文位置

這個篇章主要介紹 Spring Boot 更詳細的特性,包括構建系統,自動配置和部署,最后介紹一些最佳實踐。

13. Build Systems

強烈建議使用構建工具:Maven 或者 Gradle

13.1 Dependency Management

每個 Spring Boot 的發行版本都會提供一個可支持的依賴列表。在實際處理依賴的時候,你不需要提供版本號,版本號也由 Spring Boot 管理了。當你更新了 Spring Boot 的版本,相關的依賴也會更新對應的版本。
你仍然可以覆蓋 Spring Boot 的推薦版本來實現依賴指定的版本,但是 Spring Framework 的版本號就不要隨意更改了。

13.2 Maven

如果 Maven 用戶配置依賴了 spring-boot-starter-parent 項目,那么會繼承其默認約束:

  • Java 1.8 的編譯器
  • UTF-8 源代碼文件的編碼格式
  • 一個依賴管理的片段:管理各依賴版本的默認配置
  • repackage 的 Maven 任務
  • 智能的 resource 過濾
  • 智能的插件配置
  • 智能地處理多環境的配置文件:例如 application-dev.properties 和 applicaton-dev.yml

13.2.1 Inheriting the Starter Parent

配置 pom.xml 時候,Spring Boot 需要指定版本,如果是其他的 starter 和依賴,則可以忽略版本號。

<!-- Inherit defaults from Spring Boot -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.M3</version>
</parent>

[Spring Boot dependencies pom][spring-boot-dependencies-pom] 支持的屬性配置和依賴的默認版本查看

13.2.2 Using Spring Boot without the Parent POM

并不是每個人都喜歡繼承 spring-boot-starter-parent POM,或者你已經有自己的 parent POM,這種情況你需要顯示配置你的 Maven 配置。
在不繼承 spring-boot-starter-parent POM 的情況下,你可以通過 scope=import 依賴來獲取 Spring Boot 的依賴管理。

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.0.M3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

上面例子里面,如果你在 dependency 下面繼續添加你的個人依賴,你配置的版本號是不會生效的。為了達到自己配置第三方庫版本號的效果,你需要在配置 spring-boot-dependencies 之前就配置好第三方庫版本。例如,指定 Spring Data release train 庫的版本號如下所示:

<dependencyManagement>
    <dependencies>
        <!-- Override Spring Data release train provided by Spring Boot -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-releasetrain</artifactId>
            <version>Fowler-SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.0.M3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

13.2.3 Using the Spring Boot Maven Plugin

Spring Boot 提供了一個打包成可執行的 jar 包的 Maven 插件,無論你是否繼承 spring-boot-starter-parent,都需要添加如下配置

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

13.3 Gradle

詳情可查看《Spring Boot Gradle Plugin Reference Guide》文檔
Spring Boot 還寫了一個 jar 包,詳情可查看其 API

13.4 Ant

可以通過 Apache Ant 和 Lvy 來構建 Spring Boot 項目。spring-boot-antlib 也可以幫助 Ant 來構建出可執行的 jar。

13.5 Starters

Startes 是依賴的描述器,代表了一組依賴,使用的時候非常方便。通過 Starters,你可以得到 SPring 和其相關技術的一站式服務,而不需要自己翻閱代碼和配置詳細的依賴。例如你想使用 Spring 和 JPA 來實現數據庫訪問,只需要配置 spring-boot-starter-data-jpa 依賴即可。

Spring Boot Starters 的官方命名都有一定的格式 spring-boot-starter-*,這可以和 IDE 的自動補全結合,方便開發者編碼。由于你可以創建自己的 Starter,你的 Starter 名稱建議命名的時候項目名稱放在前面,例如 yourproject-spring-boot-starter。

org.springframework.boot 可配置的 Starters 列表。

其他社區貢獻的 Starters 可以參看 GitHub 的 README file

14. Structuring Your Code

運行 Spring Boot 不需要特定的代碼結構,然而,有些組織代碼的建議。

14.1 Using the "default" Package

你的所有類都建議放到一個特定的 package 里面,沒有指定 package 的類會歸置到 default package,這會在使用 @Component,@EntityScan,@SpringBootApplication 的時候會觸發一些問題。

14.2 Locating the Main Application Class

我們一般建議你把啟動類放在 package 的根目錄,啟動類一般是帶有 main() 方法和 @SpringBootApplication 修飾的類。
如果不想使用 @SpringBootApplication,可以用 @EnableAutoConfiguration 和 @ComponentScan 來替代。
下面是一個代碼結構的例子

com
 +- example
     +- myapplication
         +- Application.java
         |
         +- customer
         |   +- Customer.java
         |   +- CustomerController.java
         |   +- CustomerService.java
         |   +- CustomerRepository.java
         |
         +- order
             +- Order.java
             +- OrderController.java
             +- OrderService.java
             +- OrderRepository.java

15. Configuration Classes

Spring Boot 偏向于使用 Java-based 配置。雖然有可能在使用 SpringApplication 的過程中使用 XML 配置,但是我們一般建議你的主配置類是單獨的 @Configuration 類。通常來說,這個主配置類一般還會定義 main 方法。

Tip:很多已經發布到網上的 Spring 應用例子都是使用 XML 配置的,如果可以的話,盡量使用對應的 Java-based 配置。可以嘗試查找 Enable* 的注解。

15.1 Importing Additional Configuration Classes

你沒有必要把所有的 @Configuration 都放到一個類里面,通過 @Import 可以引入其他的 @Configuration 類。或者,你也可以使用 @ComponentScan 來自動掃描所有 Spring 組件,包括 @Configuration 類。

15.2 Importing XML Configuration

如果你一定要使用 XML 配置,我們建議你的主配置類還是 @Configuration 類,然后通過 @ImportResource 注解來加載 XML 配置文件。

16. Auto-configuration

Spring Boot 自動裝配會根據你應用的 jar 依賴來自動配置你的 Spring 應用。例如,如果 HSQLDB 在 classpath 上,而你還沒有手動配置任何的數據庫連接類,那么 Spring Boot 會自動裝配一個嵌入式的數據庫。
你需要選擇是否需要這個自動裝配功能,在你其中的一個 @Configuration 類是否添加 @EnableAutoConfiguration 或者 @SpringBootApplication 注解。

16.1 Gradually Replacing Auto-configuration

Auto-configuration 是非侵入性的。在任何時候,你可以定義自己的配置來替代 auto-configuration 的特定配置。例如,你添加了自己的 DataSource bean,那么默認的嵌入式數據庫就不會再啟用。
如果你需要了解 auto-configuration 都做了哪些默認配置,你可以在啟動應用的時候加上 --debug 參數,這樣就可以在日志或者控制臺上查看了。

16.2 Disabling Specific Auto-configuration Classes

如果你不想使用某個 auto-configuration 類,可以在 @EnableAutoConfiguration 注解添加 exclude 屬性來禁用這個類,代碼示例如下:

import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.*;
@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}

如果這個類不在 classpath 上,可以配置其 excludeName 屬性,內容就填寫這個類的完整類名。最后,你還可以通過 spring.autoconfigure.exclude 配置項來配置一個禁用類的列表。

17. Spring Beans and Dependency Injection

你可以使用任意 Spring 的特性來定義你的 beans 和它們的注入依賴。為簡單起見,我們經常發現使用 @ComponentScan 和 @Atuowired 都沒有問題。

如果你的代碼如上面建議一樣,可以在根目錄找到主配置類,你在添加 @ComponentScan 的時候可以不用設置參數。你應用的所有組件 (@Component,
@Service, @Repository, @Controller etc.) 都會被自動注冊為 Spring Beans。

給個 @Service 的例子:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DatabaseAccountService implements AccountService {
    private final RiskAssessor riskAssessor;
    
    @Autowired
    public DatabaseAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
    }
    // ...
}

如果你的類只有一個構造方法,你還可以省略 @Autowired 注解,如下所示:

@Service
public class DatabaseAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    public DatabaseAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
    }

    // ...

}

18. Using the @SpringBootApplication Annotation

很多 Spring Boot 開發者都愿意他們的應用使用到自動裝配,組件掃描和定義更多額外的屬性。一個 @SpringBootApplication 注解可以被用來啟用這三個特性:

  • @EnableAutoConfiguration:啟用 Spring Boot 的自動裝配機制
  • @ComponentScan:啟用組件掃描
  • @Configuration:允許在 context 注冊 bean 或者引入額外的配置類

這個 @SpringBootApplication 注解就等于 @Configuration, @EnableAutoConfiguration 和 @ComponentScan 注解的效果,如下所示:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

@SpringBootApplication 也提供了別名來配置 @EnableAutoConfiguration 和 @ComponentScan 相關的屬性。

這些特性都不是強制需要配置的,你可以其他相同功能的注解來替換 @SpringBootApplication 注解來實現你的需求。例如,你不想要組件掃描的功能,代碼如下:

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@EnableAutoConfiguration
@Import({ MyConfig.class, MyAnotherConfig.class })
public class Application {

    public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
    }

}

19. Running Your Application

把你的應用打包成 jar 和內嵌的 HTTP 服務,其中一個最大的好處就是你可以很方便地運行你的應用,而不需要特殊的 IDE 或其他插件。
當然,你也可以打包成 war 文件,你需要查閱其他的文檔。

19.1 Running from an IDE

找到 "Run as a Java Application" 的菜單并選擇執行

19.2 Running as a Packaged Application

如果你有使用 Maven 或者 Gradle 構建工具生成了一個可執行的 jar 文件,你可以通過 java -jar 來運行應用。

$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar

也可以啟用遠程調試

$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -jar target/myapplication-0.0.1-SNAPSHOT.jar

19.3 Using the Maven Plugin

Spring Boot Maven 插件包含了一個 run 程序,用來快速編譯和運行你的應用。

$ mvn spring-boot:run

你也可以使用 MAVEN_OPTS 來操作系統環境變量

$ export MAVEN_OPTS=-Xmx1024m

19.4 Using the Gradle Plugin

Spring Boot Gradle 插件包含了一個 bootRun 程序。

$ gradle bootRun

你也可以使用 JAVA_OPTS 來操作系統環境變量

$ export JAVA_OPTS=-Xmx1024m

19.5 Hot Swapping

由于 Spring Boot 應用只是普通的Java應用程序,所以 JVM Hot Swapping 可以實現。JVM Hot Swapping 在某種程度上只能做到替換字節碼文件,如果需要一個完整的解決方案,可以參考一下 JRebel

spring-boot-devtools 模塊也提供了一些可以快速重啟應用的支持,可以查看 Chapter 20,或者 Chapter 89 的 Hot Swapping。

20. Developer Tools

Spring Boot 提供了一個可以用來提升應用開發體驗的工具集 spring-boot-devtools,這個工具集默認是不啟用的,有需要可以添加如下配置

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

20.1 Property Defaults

緩存在生產環境是很有用的,但是在開發環境卻相反,因為你有可能不能及時看到你修改代碼后的效果,所以 spring-boot-devtools 默認不啟用緩存。
可以配置 application.properties 的 spring.thymeleaf.cache 項來控制緩存。
spring.http.log-request-details:可以記錄請求內容,處理的控制器和響應內容。
spring.devtools.addproperties:取消 DevTools 的默認配置。

更多默認的屬性可以參看 DevToolsPropertyDefaultsPostProcessor

20.2 Automatic Restart

當 classpath 上面的文件發生改動時,DevTools 會自動重啟應用。一般情況下,這對于快速獲取反饋很有幫助。
DevTools 會監控 classpath 所有的資源文件,保存一個類文件或者在IDE操作 Build Project 都會觸發 restart。
DevTools 和 LiveReload 搭配使用效果更好,LiveReload 在 20.3 節有詳細介紹。如果有使用 JRebel,自動重啟機制會不啟用,DevTools 的其他功能,例如 LiveReload 和 property default 仍會生效。

DevTools 在重啟應用的時候是通過 ApplicationContext's shutdown hook 來實現關閉應用,如果你有 SpringApplication.setRegisterShutdownHook(false) 的代碼,重啟機制會運行異常。

Restart vs Reload
Restart 機制是由 Spring Boot 通過兩個 ClassLoader 來實現的,不需要依賴其他的組件。一些不會改動的類,例如第三庫的 jars,會被加載到 Base ClassLoader。那些你正在開發的代碼類文件,會被加載到 Restart ClassLoader。當觸發 Restart 時,Restart ClassLoader 會被重新創建,Base ClassLoader 不做改動。這個機制會讓其 Restart 操作比冷啟動會快很多。
如果你覺得上面的機制還是不夠快,你可以借助其他組件(例如 JRebel)來實現 Reload。替換其對應的 class 字節碼文件來實現。

20.2.1 Logging changes in condition evaluation

每次重啟后,DevTools 默認會記錄增量變化的報告,可通過下面的配置項來禁用

spring.devtools.restart.log-condition-evaluation-delta=false

20.2.2 Excluding Resources

想對某些文件修改后不觸發重啟操作,可以參看下面的配置

# 修改靜態文件的默認配置
spring.devtools.restart.exclude=static/**,public/**
# 在原有的基礎上增加例外文件的配置
spring.devtools.restart.additional-exclude=filePath*

20.2.3 Watching Additional Paths

配置 spring.devtools.restart.additionalpaths 項
一般會和 spring.devtools.restart.exclude 配置項搭配使用

20.2.4 Disabling Restart

配置 spring.devtools.restart.enabled 項來不啟用重啟機制,這種情況下,Restart ClassLoader 還是會被初始化,只是他不會在監控任何文件的改動。
如果想完全禁用重啟機制,那么在調用 SpringApplication.run() 方法前設置其變量為 false。

public static void main(String[] args) {
    System.setProperty("spring.devtools.restart.enabled", "false");
    SpringApplication.run(MyApp.class, args);
}

20.2.5 Using a Trigger File

你經常使用 IDE 來編碼,可能更希望在特定的時機重啟,可以通過監控一個特殊文件來實現。
配置 spring.devtools.restart.trigger-file 項

20.2.6 Customizing the Restart Classloader

上面的章節有描述 Restart ClassLoader 和 Base ClassLoader,正常情況下,你在 IDE 的代碼都會被加載到 Restart ClassLoader,如果你在 IDE 里面有多個模塊,而有些模塊是不經常改動,那么你可以通過添加 META-INF/spring-devtools.properties 文件來配置特殊的邏輯。
spring-devtools.properties 文件的配置內容都必須以 restart.exclude 或者 restart.include 開頭,restart.exclude 表示加載到 Base ClassLoader,restart.exclude 表示加載到 Restart ClassLoader。

restart.exclude.companycommonlibs=/mycorp-common-[\\w-]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w-]+\.jar

20.2.7 Known Limitations

重啟功能在某些場景下運行不是很好,例如在用 ObjectInputStream 做對象轉換的時候。

20.3 LiveReload

spring-boot-devtools 模塊有一個嵌入式的 LiveReload 服務,這個服務可以用來在資源文件改變后觸發瀏覽器刷新頁面。LiveReload 瀏覽器插件可以從 livereload.com 獲取,支持 Chrome,Firefox 和 Safari。

如果不想啟用 LiveReload 服務,把 spring.devtools.livereload.enabled 屬性配置為 false 即可。

同一時間你只能運行一個 LiveReload 服務,所以在啟動你的應用之前,確認是否有其他的 LiveReload 服務在運行。如果你在 IDE 啟動多個應用,只有第一個啟動的應用可以正常使用 LiveReload 服務。

20.4 Global Settings

在用戶目錄添加 ~/.spring-boot-devtools.properties 文件,里面的配置會對這臺機器上面所有的 Spring Boot 應用都會生效。

20.5 Remote Applications

spring-boot-devtools 并不只是限制在本地使用,還有一些功能是針對遠程應用的。遠程支持的功能是可選的,若要啟用這個功能,依賴配置如下:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludeDevtools>false</excludeDevtools>
            </configuration>
        </plugin>
    </plugins>
</build>

還需要設置 spring.devtools.remote.secret 屬性,例如:

spring.devtools.remote.secret=mysecret

Warning: 啟用 spring-boot-devtools 的遠程功能會有安全風險,生產環境不能開啟該功能。

遠程功能包含兩個部分:一個是接收連接的服務端和一個在你 IDE 運行的客戶端。當 spring.devtools.remote.secret 屬性被設置有值的時候,服務端會自動啟用該功能,客戶端需要手動啟動。

20.5.1 Running the Remote Client Application

遠程功能的客戶端就是被設計在 IDE 運行的。在客戶端,你需要使用和遠程項目相同的 classpath 來運行org.springframework.boot.devtools.RemoteSpringApplication。客戶端應用唯一需要的參數就是它要連接遠程項目的 URL。

例如,你在使用 Eclipse 或者 STS,有一個項目 my-app ,部署到了 Cloud Foundry,那你需要進行如下操作:

  • Select Run Configurations… from the Run menu.
  • 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).

一個運行遠程功能的客戶端啟動日志大概如下:

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: 2.1.0.M3
2015-06-10 18:25:06.632 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication :
spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code/springboot-
samples/spring-boot-sample-devtools)
2015-06-10 18:25:06.671 INFO 14938 --- [ main] s.c.a.AnnotationConfigApplicationContext :
Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup
date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
2015-06-10 18:25:07.043 WARN 14938 --- [ main] o.s.b.d.r.c.RemoteClientConfiguration : The
connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2015-06-10 18:25:07.074 INFO 14938 --- [ main] o.s.b.d.a.OptionalLiveReloadServer :
LiveReload server is running on port 35729
2015-06-10 18:25:07.130 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication :
Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)

Note: 因為客戶端使用的 classpath 和真正的應用是一樣的,所以它能直接讀取到應用的屬性配置。這就是 spring.devtools.remote.secret 配置項如何被讀取并傳給服務端認證的原理。

Tip: 建議使用 https 協議作為傳輸協議,那么傳輸內容是加密的,所以密碼等信息就不會被攔截。

Tip: 如果你通過代理來訪問服務端,那么需要配置 spring.devtools.remote.proxy.host 和 spring.devtools.remote.proxy.port 這兩個屬性。

20.5.2 Remote Update

客戶端會監控你應用 classpath 的文件變化,這個本地重啟(20.2節 Automatic Restart)的機制一樣。所有的文件更新都會推送到服務端,必要時會觸發重啟操作。這在云服務上迭代開發一個功能的場景下會非常有幫助,因為通常來說,服務端的更新和重啟會比全部重啟和循環部署快很多。

Note: 文件只有在客戶端運行時才會被監控,如果你在啟動客戶端前修改的文件,這個變化便不會推送到服務端。

21. Packaging Your Application for Production

Executable jar 可以用來發布到生產環境。由于他們都自帶容器,所以非常適用于基于云平臺的部署。

更多關于可用于生產的功能,可以考慮添加 spring-boot-actuator 庫,可參看文檔 Part V, “Spring Boot Actuator: Production-ready features”

22. What to Read Next

你現在應該知道如何使用 Spring Boot 和應該遵循的一些最佳實踐,可以繼續深入了解 Spring Boot 特定的功能,或者你跳過這部分去了解關于生產部署方面的功能。

相關文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375