[菜鳥讀源碼]halo✍源碼學習(一)

       Halo是一款現代化的我的獨立博客系統,給習慣寫博客的同窗一個更好的選擇。 聽說這是一個較容易讀懂的Spring-Boot項目,那我就但願經過這個項目學習前輩的經驗。java

       若有幫助,不勝榮幸。若有錯誤,歡迎指正!web

前言

       最先看到這個博客的源碼的時候是經過B站up主-CodeSheep的一個視頻:Java企業級開源項目推薦,幫助你們從學習走向實踐,奈何當時本身知識有限,沒有仔細的閱讀源碼。近日Halo也推出了正式版,我也就抱着學習的心態拜讀一下。spring

       首先打開工程,看到整個工程有如下兩個明顯的變化:api

  • 配置文件由properties變爲yaml

       能夠明顯的看到,在處理層級關係的時候,properties須要使用大量的路徑來描述層級(或者屬性),好比environments.dev.url和environments.dev.name。其次,對於較爲複雜的結構,好比數組(my.servers),寫起來更爲複雜。而對應的YAML格式文件就簡單不少:數組

  • 構建工具由meavn變爲gradle

       由於此前有過Android的開發經驗,因此這一改變對個人影響並不大😄。gradle逐漸替代meavn應該是目前的趨勢,可是目前大部分教學和企業採用的仍是以meavn爲主,因此此前我也不曾嘗試過採用gradle構建項目。由此看出Halo仍是很Fashion的👍。tomcat

Application

       首先打開Application.java文件,看看有什麼學習的地方🤤。bash

@SpringBootApplication
@EnableJpaAuditing
@EnableScheduling
@EnableAsync
@EnableJpaRepositories(basePackages = "run.halo.app.repository", repositoryBaseClass = BaseRepositoryImpl.class)
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        // Customize the spring config location
        System.setProperty("spring.config.additional-location", "file:${user.home}/.halo/,file:${user.home}/halo-dev/");

        // Run application
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        System.setProperty("spring.config.additional-location", "file:${user.home}/.halo/,file:${user.home}/halo-dev/");
        return application.sources(Application.class);
    }
}
複製代碼

       發現與我以前Spring-Boot開發兩點不同的地方:服務器

       其一:繼承SpringBootServletInitializer從而實現configure方法架構

       可能找答案的姿式不對,只零星找到下面幾點描述:app

       一、啓動類繼承SpringBootServletInitializer類,重寫 configure(SpringApplicationBuilder builder`)方法

       二、由於想要用web容器啓動項目

       三、使用外部 servlet 容器

結論:爲了Undertow容器!

       緣由:

一、排除內置的tomcat容器-build.gradle

exclude module: 'spring-boot-starter-tomcat'
複製代碼

二、添加Undertow依賴-build.gradle

implementation 'org.springframework.boot:spring-boot-starter-undertow'
複製代碼

三、配置服務器

server:
 port: 8090
 use-forward-headers: true
 undertow:
 io-threads: 2
 worker-threads: 36
 buffer-size: 1024
 directBuffers: true
複製代碼

       結合此前在別人基礎上修改的網盤項目獲得了相同的印證。

       其二:System.setProperty("spring.config.additional-location", "...");

       開發者給瞭如下注釋:Customize the spring config location(定製spring配置文件的位置)

       存在如下三個疑問:

       一、System.setProperty有何用?

       setProperty (String prop, String value); 一、 設置指定鍵對值的系統屬性,其中prop:系統屬性的名稱,value:系統屬性的值。注:這裏的system,系統指的是 JRE (runtime)system,不是指 OS。 二、System.setProperty至關於一個靜態變量,存在內存裏面,能夠在項目的任何一個地方,經過System.getProperty("變量")來得到

       二、爲什麼要設定這個變量?

       加載外部配置文件。打包jar運行也不方便修改jar內部數據,經過設置環境變量spring.config.location。由於博客中也有不少配置選項,因此猜測須要從外部讀取某些會改變的配置,須要繼續閱讀源碼驗證猜測。

       三、${user.home}從何而來?

       如從前所示user.home應該是一個靜態變量,嘗試打印:

System.out.println(System.getProperty("user.home"));
//打印出:C:\Users\74472 驗證猜測成功
複製代碼
變量 含義
java.version Java 運行時環境版本
java.vendor Java 運行時環境供應商
java.vendor.url Java 供應商的 URL
java.home Java 安裝目錄
java.vm.specification.version Java 虛擬機規範版本
java.vm.specification.vendor Java 虛擬機規範供應商
java.vm.specification.name Java 虛擬機規範名稱
java.vm.version Java 虛擬機實現版本
java.vm.vendor Java 虛擬機實現供應商
java.vm.name Java 虛擬機實現名稱
java.specification.version Java 運行時環境規範版本
java.specification.vendor Java 運行時環境規範供應商
java.specification.name Java 運行時環境規範名稱
java.class.version Java 類格式版本號
java.class.path Java 類路徑
java.library.path 加載庫時搜索的路徑列表
java.io.tmpdir 默認的臨時文件路徑
java.compiler 要使用的 JIT 編譯器的名稱
java.ext.dirs 一個或多個擴展目錄的路徑
os.name 操做系統的名稱
os.arch 操做系統的架構
os.version 操做系統的版本
file.separator 文件分隔符(在 UNIX 系統中是「/」)
path.separator 路徑分隔符(在 UNIX 系統中是「:」)
line.separator 行分隔符(在 UNIX 系統中是「/n」)
user.name 用戶的帳戶名稱
user.home 用戶的主目錄
user.dir 用戶的當前工做目錄

測試運行

       Spring-Boot的項目運行起來仍是比較簡單的🤪。頁面也很美觀👍

Halo博客

Controller學習

       Spring-boot的項目一般都是從Controller讀起,發現一個共同的特色,就是代碼都是相似這樣一個結構:

private final PostService postService;

private final OptionService optionService;

... .... // 其餘的Service

private final ThemeService themeService;

public ContentIndexController(PostService postService, OptionService optionService, ThemeService themeService) {
    this.postService = postService;
    this.optionService = optionService;
    ... .... // 其餘的Service
    this.themeService = themeService;
}

@GetMapping
public String index(Model model) {
    return this.index(model, 1, Sort.by(DESC, "topPriority").and(Sort.by(DESC, "createTime")));
}

 @GetMapping(value = "page/{page}")
public String index(Model model, @PathVariable(value = "page") Integer page, @SortDefault.SortDefaults({ @SortDefault(sort = "topPriority", direction = DESC), @SortDefault(sort = "createTime", direction = DESC) }) Sort sort) {
    ...//省略 
}
複製代碼

       學習收穫一:使用構造器注入須要用到的Service

       學習收穫二:使用多態處理請求

       真正起做用的是後者,前者只是爲用戶添加了參數後調用後者。

return this.index(model, 1, Sort.by(DESC, "topPriority").and(Sort.by(DESC, "createTime")));
複製代碼

       學習收穫三:RESTful的api設計

相關文章
相關標籤/搜索