# spring-boot-boilerplate-java **Repository Path**: yanwenkun/spring-boot-boilerplate-java ## Basic Information - **Project Name**: spring-boot-boilerplate-java - **Description**: Spring Boot 样板项目(使用 Java 与 Maven) - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2020-02-24 - **Last Updated**: 2021-12-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README :toc: :toc-title: 目录 :author: YAN Wenkun :email: code@yanwk.fun = Spring Boot 样板项目(使用 Java 与 Maven) 本样板项目基于 https://spring.io/[Spring] 官方的 https://start.spring.io/[Spring Initializr] 生成的 https://spring.io/projects/spring-boot/[Spring Boot] 项目, 并添加一些实用的常见配置,便于在新项目启动时“简单修改即可复用”。 同时,本项目也将不断跟进上游最新版本,以便下游项目一站式更新。 本项目以容器或云引擎(例: https://www.aliyun.com/product/sae[阿里云 SAE] )为部署目标,简化传统的复杂配置,减少更新维护成本。 文件目录结构: ---- spring-boot-boilerplate-java │ .editorconfig │ .gitattributes │ .gitignore │ docker-compose.yml │ Dockerfile │ LICENSE │ mvnw │ mvnw.cmd │ pom.xml │ README.adoc │ ├─.mvn │ └─wrapper │ maven-wrapper.jar │ maven-wrapper.properties │ MavenWrapperDownloader.java │ ├─docs │ │ Upgrade-Checklist.adoc │ │ │ ├─logback │ │ logback-spring.xml.example │ │ logback-spring.xml.file.example │ │ logback-spring.xml.jdbc.example │ │ logback-spring.xml.sls.example │ │ README.logback.adoc │ │ │ └─maven │ settings.xml │ settings.xml.more-repos.example │ └─src ├─main │ ├─java │ │ └─com │ │ └─example │ │ └─demo │ │ DemoApplication.java │ │ │ └─resources │ │ application-dev.yml │ │ application-prod.yml │ │ application.yml │ │ │ ├─static │ │ .gitkeep │ │ │ └─templates │ .gitkeep │ └─test └─java └─com └─example └─demo DemoApplicationTests.java ---- == 项目信息 * 构建工具:Maven * Java 版本:17 与 https://start.spring.io/[Spring Initializr] 生成的 https://spring.io/projects/spring-boot/[Spring Boot] 项目相比,有如下变动: * git 行为配置 ** 一个通用的 `.gitignore` 文件(规定 git 自动忽略哪些文件) ** 一个通用的 `.gitattributes` 文件(规定 git 对文本格式的处理) ** 为空目录添加 `.gitkeep` 文件(0字节,仅占位,避免空目录被忽略) * 编辑器行为配置 ** 以 `.editorconfig` 文件来规范字符编码、行尾、文件末尾、缩进格式等 * Maven Wrapper 使用【阿里云】中国大陆的下载地址,改善下载速度 ** Maven 仓库源并未配置到国内,请参照 <<配置 Maven 使用镜像源>> 进行配置 * 包含一个基本的 `README.adoc` 自述文件,以便参考 AsciiDoc 语法 ** AsciiDoc 兼容 Markdown 语法,可在 `adoc` 中直接写 Markdown * 配置文件使用 YAML 格式( `application.yml` 取代 `application.properties` ) * 两个项目配置集 ** 两个 Maven Profile: `dev`, `prod` ** 两个 Spring Profile: `dev`, `prod` ** 启用 Maven Profile `prod` 会自动启用对应的 Spring Profile `prod`。而 `dev` 亦然 * Docker 描述文件(`Dockerfile`、`docker-compose.yml`) ** 参照官方最佳实践,使用多段构建 * `docs` 目录下附带若干帮助文件 ** 版本升级清单 ** Logback 日志配置样例 ** Maven 镜像源配置样例 == 运行指引 * 如果你使用 Intellij IDEA / Spring Tool Suite,直接运行项目即可。 === 使用命令行运行 * 如果你不想使用 IDE,可以用命令行的方式运行 Spring Boot 项目,你需要先在本地安装: ** Git ** JDK 17 或更高版本 执行命令: [source,sh] ---- git clone https://github.com/yanwenkun/spring-boot-boilerplate-java.git cd spring-boot-boilerplate-java ./mvnw clean spring-boot:run ---- 按 `Ctrl + C` 可终止运行。 === 使用 Docker Compose 运行 如果你安装有 Docker Desktop,直接运行以下命令,即可构建镜像并运行容器: [source,sh] ---- git clone https://github.com/yanwenkun/spring-boot-boilerplate-java.git cd spring-boot-boilerplate-java docker-compose up --build ---- 按 `Ctrl + C` 可终止运行。 == 修改成你的项目 1. 全局搜索 `DemoApplication` ,并替换为你的程序名称,比如 `SampleApplication` (建议保留 `Application` 后缀) 2. 全局搜索 `com.example.demo` ,并替换为你的软件包名称,比如 `fun.yanwenkun.sample` 3. 全局搜索 `com.example` ,并替换为你的组织名称,比如 `fun.yanwenkun` 4. 修改 `pom.xml` 中的软件制品信息(GAV),并管理你的依赖项 5. 修改代码文件对应的路径、文件名(可通过 IDE 的重构功能完成) 6. 修改 `docker-compose.yml` 中的容器与镜像名称 == 配置集的使用 .配置集与运行环境样板 |=== |启用配置集 |运行环境 |数据源 |日志级别(业务) |日志级别(框架) |`@Profile("dev")` |开发环境 Development |运行时 H2 内存数据库 |TRACE |INFO .3+|`@Profile("prod")` |线上测试环境 Testing |测试数据库 |DEBUG |INFO |预发环境 Staging |生产数据库 |INFO |WARN |生产环境 Production |生产数据库 |WARN |ERROR |=== 在实际生产中,该表会更为复杂,但原则不变:使问题尽早暴露、尽早解决。 + 从脱离本地开发环境开始,所有代码与依赖项均应与生产环境一致,仅配置不同。 + === Profile 用法 * Spring Profile 在 Java/Kotlin 代码中的用法: ** 使用Spring注解: `@Profile("dev")` ** 未标 `@Profile` 注解的代码段,均与配置集无关 * Maven Profile 不关心 Java 代码中的注解,只关心编译资源(依赖项),`pom.xml` 中对此有举例 === 以配置集运行 * 使用 IDE 可以直接切换配置集 * 默认激活: `dev` * 以 `prod` 运行: [source,sh] ---- ./mvnw clean spring-boot:run -P prod ---- * 如何修改默认配置集: ** 修改 `pom.xml` 中的 `activeByDefault` 属性 ** 注意仅保持 1 个 `activeByDefault` 为 `true` *** Maven 可以同时激活多个 Profile,但 Spring 只允许同时激活一个 * `Dockerfile` 已配置为默认使用 `prod` * 编译服务如 Jenkins 应配置相关参数,代码仓库本身应面向开发者 == 日志的配置 * 容器环境下,日志输出到 STDOUT(标准输出、命令行输出)即可,由容器管理日志的收集 * 程序只需要配置日志输出等级,修改 `application-{$profile}.yml` 即可 * 如需详细配置 Logback,请参考本项目中的 link:docs/logback/README.logback.adoc[Spring Logback 日志配置参考] 建议: * 编写代码时不要用 `System.out.println()`,而是使用 Slf4j 分等级记录日志 ** 可用等级(从低到高): `TRACE` `DEBUG` `INFO` `WARN` `ERROR` ** Lombok 可以使用 @Slf4j 注解减少代码,但本项目没有引入该依赖 == 附录一:JDK 的选择 === Oracle JDK 的收费背景 * 在以往几乎完全免费的 https://www.oracle.com/java/technologies/downloads/[Oracle JDK] ,从2019年开始,只对开发、个人使用免费,用于生产环境需要付费 * 在 2021 年 9 月发布的 Oracle JDK 17,又可以免费用于生产环境了,但只提供三年支持。三年之后要么升级大版本,要么付费买支持,要么停留在最后的免费版本(不安全) * 而完全免费的 https://jdk.java.net/[Oracle OpenJDK] 只更新最新 GA 大版本,每当新的大版本 GA,老版本即停止更新 ** Oracle 这么做是为了鼓励开发者跟进新版本,同时也扩大老版本的维护收费 * 个人建议 ** 对于企业开发,“追新”是为了保持先进、与主流同步,“追最新”则容易踩坑、增加成本。正所谓“领先一步是先驱,领先两步是先烈” :-) ** Java 的下一个长期支持版本(LTS)是 21,预计 2023 年 9 月推出,在其广泛可用(GA)之前,建议维持在 Java 17 === 使用其它提供方的 OpenJDK 考虑以下几点: * 开源 * 有健壮支持 * 完全免费 推荐如下: * https://adoptium.net/[Eclipse Temurin] ** 即原先的 AdoptOpenJDK + HotSpot ** 来自 Java 社区重要成员支持的 OpenJDK ** 涵盖大版本较广(8、11、16、17、18 …) ** 老版本(< 16)提供 JRE * https://developer.ibm.com/languages/java/semeru-runtimes/downloads[IBM Semeru] ** 即原先的 AdoptOpenJDK + OpenJ9 ** `OpenJ9` 是来自 IBM 的开源 JVM,为云环境、容器化优化,内存占用小,提供快速启动选项 ** 除了 JDK 之外,每个版本还提供 JRE * http://dragonwell-jdk.io/[Alibaba Dragonwell] ** 阿里巴巴开源的 OpenJDK ** 为 LTS 版本提供长期支持 ** 随阿里云的工具链分发 * https://aws.amazon.com/corretto[Amazon Corretto] ** 亚马逊开源的 OpenJDK ** 为 LTS 版本提供长期支持 如果你感到选择困难,请使用 https://adoptium.net/[Eclipse Temurin] ,它的兼容性最佳。 == 附录二:配置集的理解 * Profile 直译即“档案”,此处理解为配置、配置集 * 配置集包含:配置项 + 专有依赖 + 专有代码 * 对于代码本身,为避免过度复杂,仅使用 2 个配置集: ** 开发阶段专有代码: `@Profile("dev")` ** 生产阶段专有代码: `@Profile("prod")` === Profile 与 Profile 的不同 * 在本项目中有两种 Profile: 1. Spring Profile 2. Maven Profile * 两者的实际作用域不同 ** Spring Profile 关心代码与配置项 ** Maven Profile 关心编译与依赖项 * 为了便于统一管理,本项目中 Spring Profile 和 Maven Profile 共用同一套名称,并通过配置上的绑定,对两者进行了关联 ** 比如,Maven 启用了 `prod`,Spring 也会启用 `prod` ** 但反过来不会 * 如果配置不当,这两种 Profile 可能会冲突 ** 同一时间只能有一个 Spring Profile 激活 ** 同一时间可以有多个 Maven Profile 激活(在本项目中不推荐这么做) === Profile 的命名 * `dev` 与 `prod` 两个命名是 Java 世界中的常见习惯,简洁明了,本项目尊重该习惯 * Profile 命名并无绝对标准,比如 https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#profile-specific-configuration[Spring 官方文档] 中就使用了 `dev`、`staging`、`production` 作为例子 * 为了避免开发者误解“Profile”与“运行环境”之间的关系,本项目仅使用 `dev` 与 `prod` 这两个 Profile ** `dev` 仅在开发环境有效,脱离开发环境即开始使用 `prod`,使潜在问题尽早暴露 实际上,在高度 CI/CD 化之后,开发者不需要过多关心运行环境,而是应该精简配置、写好配置样板,供运维在不同阶段灵活部署。 某种意义上,这两个 Profile 的含义可以理解为 `DEBUG` 与 `RELEASE`,或者 `local` 与 `online`。 === 概念上的简化 * 开发(本地编码)、验证(各类测试)、生产(发布上线): 1. 既是软件生命周期中的“阶段” 2. 也是运维与服务治理中的“环境” * 分得过于详细,有过度设计之虞,概念越多越容易出错 * 作为“偷懒”的做法,将阶段和环境合为一谈,主要目的在于减少心智负担 ** 但扩大开发规模的时候,还是要注意概念上的区分 === 更多信息 * Maven 与 Spring 共用 Profile name 并不是高枕无忧的设计 ** 主要看 Profile 是否与自动化流水线能够流畅配合 * 如果不需要 Maven 根据环境/阶段管理不同的依赖,可以在 `pom.xml` 中删除 `Profiles` 相关定义 ** 如果去掉了 Maven Profiles,可以使用环境变量,使 Spring Boot 程序运行时直接调用不同配置集: [source,sh] ---- export SPRING_PROFILES_ACTIVE=prod ---- == 附录三 === 版本升级清单 见: link:docs/Upgrade-Checklist.adoc[版本升级清单] 。 === 为什么不默认使用 Lombok 从工程管理的角度出发,Java 项目保持其代码风格的延续是很重要的。而 Lombok 的侵入性,对老项目而言是需要权衡的,请根据团队的意见做出选择。 对于没有历史负担的新项目,可以考虑 https://github.com/yanwenkun/spring-boot-boilerplate-kotlin[Kotlin] 。 === 使用 Maven 构建 Docker 镜像 在不配置 Maven 插件(即不改动 `pom.xml`)的前提下,最简单的方法是使用命令行调用 Google Jib: * 用法1:构建镜像 [source,sh] ---- ./mvnw com.google.cloud.tools:jib-maven-plugin:dockerBuild -Dimage="example/demo:dev" ---- * 用法2:构建镜像并推送至仓库(Docker Registry) [source,sh] ---- ./mvnw com.google.cloud.tools:jib-maven-plugin:build -Dimage="example/demo:dev" ---- 注意修改镜像名称与标签 `example/demo:dev`。 + 推送至仓库前需要先登录(`docker login`)。 === 配置 Maven 使用镜像源 在中国大陆访问 Maven 官方源一般会很慢,建议使用镜像源。 * 不推荐直接在 `pom.xml` 中配置仓库来源 ** 因为初次构建时还是要从官方源下载包,依然很慢 ** 不利于 CI 的管理 如何配置本地 Maven 使用镜像源: 将【 link:docs/maven/settings.xml[settings.xml] 】复制到【 用户主目录/.m2/ 】下。 或执行命令: [source,sh] ---- mkdir ~/.m2/ cp docs/maven/settings.xml ~/.m2/ ---- 如需 Maven Central 以外的仓库源,请参考【 link:docs/maven/settings.xml.more-repos.example[settings.xml.more-repos.example] 】。 == 许可 本项目使用与 https://github.com/spring-projects/spring-boot[Spring Boot] 一致的 Apache License 2.0 许可。