Halo是一款现代化的个人独立博客系统,给习惯写博客的同学一个更好的选择。据说这是一个较容易读懂的Spring-Boot项目,那我就希望通过这个项目学习前辈的经验。
如有帮助,不胜荣幸。如有错误,欢迎指正!
最早看到这个博客的源码的时候是通过B站up主- CodeSheep 的一个视频: Java企业级开源项目推荐,帮助大家从学习走向实践 ,奈何当时自己知识有限,没有仔细的阅读源码。近日Halo也推出了正式版,我也就抱着学习的心态拜读一下。
首先打开工程,看到整个工程有以下两个明显的变化:
可以明显的看到,在处理层级关系的时候,properties需要使用大量的路径来描述层级(或者属性),比如environments.dev.url和environments.dev.name。其次,对于较为复杂的结构,比如数组(my.servers),写起来更为复杂。而对应的YAML格式文件就简单很多:
因为此前有过Android的开发经验,所以这一改变对我的影响并不大:smile:。gradle逐渐替代meavn应该是目前的趋势,但是目前大部分教学和企业采用的还是以meavn为主,所以此前我也未曾尝试过采用gradle构建项目。由此看出Halo还是很Fashion的:+1:。
首先打开 Application.java
文件,看看有什么学习的地方 。
@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开发两点不一样的地方:
可能找答案的姿势不对,只零星找到下面几点描述:
1、启动类继承SpringBootServletInitializer类,重写 configure(SpringApplicationBuilder builder`)方法
2、因为想要用web容器启动项目
3、使用外部 servlet 容器
原因:
1、排除内置的tomcat容器-build.gradle
exclude module: 'spring-boot-starter-tomcat'
2、添加Undertow依赖-build.gradle
implementation 'org.springframework.boot:spring-boot-starter-undertow'
3、配置服务器
server: port: 8090 use-forward-headers: true undertow: io-threads: 2 worker-threads: 36 buffer-size: 1024 directBuffers: true
结合此前在别人基础上修改的网盘项目得到了相同的印证。
开发者给了以下注释: Customize the spring config location
(定制spring配置文件的位置)
存在以下三个疑问:
1、System.setProperty有何用?
setProperty (String prop, String value); 1、 设置指定键对值的系统属性,其中prop:系统属性的名称,value:系统属性的值。注:这里的system,系统指的是 JRE (runtime)system,不是指 OS。 2、System.setProperty相当于一个静态变量,存在内存里面,可以在项目的任何一个地方,通过System.getProperty("变量")来获得
2、为何要设定这个变量?
加载外部配置文件。打包jar运行也不方便修改jar内部数据,通过设置环境变量spring.config.location。因为博客中也有很多配置选项,所以猜想需要从外部读取某些会改变的配置,需要继续阅读源码验证猜想。
3、${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的项目运行起来还是比较简单的 。页面也很美观:+1:
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) { ...//省略 }
真正起作用的是后者,前者只是为用户添加了参数后调用后者。
return this.index(model, 1, Sort.by(DESC, "topPriority").and(Sort.by(DESC, "createTime")));