Spring Boot 的代码示例演示
Spring Boot 诞生背景和核心体系
诞生背景
在 2014 年 Spring Boot 1.0 正式发布之前,Java 开发者正经历着一段 “黑暗时期”:
- XML 配置地狱: 那时的 Spring 被戏称为“配置框架”。写一个简单的 Hello World,你可能需要配置数百行的 XML 文件。开发者自嘲:“半天写代码,半天调配置”。
- 微服务浪潮的倒逼: 2013 年前后,Martin Fowler 提出了
微服务(Microservices) 概念。微服务要求把一个大系统拆成几十个小服务。如果每个小服务都要折腾半天配置、手动部署 Tomcat,那开发效率将是毁灭性的。 - 竞争对手的压力: 当时 Node.js 和 Python 的 Web 框架(如 Express, Flask)以“几行代码启动服务”的简洁性吸引了大量开发者。Spring 必须进化,否则就会被时代抛弃。
于是,Pivotal 团队在 2014 年 推出了 Spring Boot,目标只有一个:让 Spring 再次变得简单。
核心体系
Spring Boot 并不是凭空创造的新技术,它是站在 Spring 这个巨人肩膀上的“自动化管家”。它的核心理念是:约定优于配置 (Convention over Configuration)。
- 自动配置 (Auto-Configuration) —— 告别配置地狱:
- 以前你需要手动告诉 Spring:“我要用 MySQL,驱动是这个,连接池是那个”。
- Spring Boot 的出现,就如同智能手机。以前的手机连 WiFi 要设置 IP、子网掩码、网关;现在的手机只要点一下 WiFi 名,剩下的它自己搞定。
- Spring Boot 启动时会利用 @EnableAutoConfiguration 扫描你引入的 jar 包。如果你引入了 Redis 的包,它就推断你要用 Redis,并自动在内存里帮你创建好 RedisTemplate 实例。
- 起步依赖 (Starter POMs) —— 依赖管理标准化:
- 以前引入 A 包,可能需要手动引入 B、C、D 及其对应的兼容版本,经常发生版本冲突(依赖地狱)。
- 而 Spring Boot 就像点外卖套餐。你不用单点米饭、肉、筷子,直接点一个 “鱼香肉丝套餐”,所有配套的东西由餐厅(Spring 官方)帮你配好。
- 它将原本分散的依赖进行了垂直打包。比如引入 spring-boot-starter-web,它会自动帮你下载 Spring MVC、Jackson(JSON解析)、Tomcat 等一整套经过官方兼容性测试的组件。
- 内嵌容器 (Embedded Containers) —— 迈向云原生:
- 以前部署 Java 应用需要:安装 Tomcat -> 配置环境变量 -> 拷贝 war 包。这在需要快速扩容的云环境中太慢了。
- 以前你要跑代码,得先买个大冰箱(Tomcat)把菜塞进去。现在 Spring Boot 把冰箱缩小成一个 “车载冷藏箱”,直接集成在菜里,提着就能走。
- 打包后的 Spring Boot 程序是一个独立的 “.jar” 文件。通过 “java -jar” 命令直接启动,因为服务器(Tomcat/Jetty)已经作为代码的一部分运行了。这是实现 Docker 容器化 和 CI/CD 自动化部署 的前提。
三分钟开发一个 SB 应用
可以参考《Spring Boot 简介及 hello world 应用的编写》、《RESTful 简介以及基于 SSM 的完整案例》、《Redis 集群搭建之主从哨兵客户端演示》、《Redis 集群搭建之集群cluster模式的客户端构建》、《Redis 支持读写分离的 RedisJSON 客户端组件》、《Redis 集群模式下支持读写分离的 RediSearch 简单自研组件》、《Redis 高级客户端 Redisson 的使用》 、《Shiro的工程实践》等等。
两种 POM 的组织方式
第一种方式:继承派
这是官方最推荐新手使用的方式,也是 “全家桶” 模式。优点是极简且省心,SB 自动配置了 Java 编译版本、编码格式(UTF-8)、资源过滤(Resource Filtering), 预置了大量的插件配置(如 spring-boot-maven-plugin),你不需要自己写插件的版本号。缺点是太霸道,Maven 的 parent 标签是单继承的。如果你所属的公司要求项目必须继承公司统一的 “企业父 POM”(例如 company-parent),这种方式就直接哑火了。
1 | <parent> |
第二种方式:组合派
这是一种 “按需取经” 的模式。优点是自由解耦,不占用 parent 位置。你的项目可以继承自公司的父 POM,同时依然享受 Spring Boot 的版本管理。它只负责 “统一版本号”,不会强加给你额外的资源过滤配置或插件设置。缺点是稍显琐碎,你需要手动配置 Java 编译版本,且在使用 spring-boot-maven-plugin 等插件时,必须手动指定版本号。
1 | <properties> |
在实际正规的商业开发中,通常采用 “公司父 POM + Spring Boot 导入” 的组合模式,这为架构扩展留出了余地。
1 | <project> |
关于依赖的查找顺序
Maven 并不是同时对比所有仓库看谁优先级高,而是按照 由近及远 的顺序查找:
- 本地仓库 (Local Repository):你的 localRepository 文件夹(默认 .m2/repository)。如果有,直接用。
- 远程仓库 (Remote Repositories):如果本地没有,就开始找远程的。寻找顺序如下:
- 第一步:检查 settings.xml 中的 profiles。
- 第二步:检查 pom.xml 中的 repositories。
- 第三步:如果以上都没配置,最后找 Maven 默认的 Central。
- mirrorOf 不是参与排队的优先级,它是强行拦截:不管你在 pom.xml 里配置了多少个 repository,一旦 settings.xml 中配置了
*(镜像所有),Maven 会无视你配置的所有 URL,强行把请求发往镜像地址。
执行远程访问时,如果在 settings.xml 的 activeProfiles 里配置了仓库,它们最先被访问。settings.xml 示例:
1 |
|
POM 文件中的 Profiles:
1 | <!--第一步:在 pom.xml 中定义 Profile--> |
构建一个最基础的应用框架
这个初始项目主要介绍了一些开发中的一些常用技术,包括:怎样热部署、swagger文档管理、典型的分环境配置文件、springmvc常用技术、典型的logback-spring日志、MybatisPlus型ORM框架(内置接口及简化开发方式、创建和更新时间处理、业务字段、敏感字段、逻辑删除字段、枚举字段、自定义mapper接口或配置接口、分页插件和自定义分页查询、简单多表查询)、参数各种校验及分组校验、lombok和mapstruct简化开发等。
依赖配置
pom.xml
1 |
|
日志文件配置
src/main/resources/logback-spring.xml
1 |
|
主要配置文件
application.yml
1 | spring: |
application-dev.yml
1 | logging: |
application-prod.yml
1 | spring: |
启动类
1 |
|
主要配置类
WebConfig
1 | import com.koohub.demo01.interceptor.LoginInterceptor; |
MybatisPlusConfig
1 | import com.baomidou.mybatisplus.annotation.DbType; |
MybatisPlusHandler
1 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
MapStructConfig
1 | import org.mapstruct.MapperConfig; |
公共的 Model
BaseEntity
1 |
|
BasePageQuery
1 |
|
PageResult
1 |
|
ValidGroups
1 | public interface ValidGroups { |
Result
1 |
|
ResultCode
1 |
|
字典或枚举
OrderStatusEnum
1 | import com.baomidou.mybatisplus.annotation.EnumValue; |
异常处理类
GlobalExceptionHandler
1 | import com.koohub.demo01.model.common.Result; |
拦截器
LoginInterceptor
1 | public class LoginInterceptor implements HandlerInterceptor { |
文件的上传下载业务
UploadController
1 | import com.koohub.demo01.model.common.Result; |
用户业务
UserRestController
1 |
|
UserService
1 | import com.baomidou.mybatisplus.extension.service.IService; |
UserServiceImpl
1 |
|
UserConvert
1 | import com.koohub.demo01.config.MapStructConfig; |
UserMapper
1 | package com.koohub.demo01.mapper; |
resources/mapper/UserMapper.xml
1 |
|
UserEntity
1 |
|
BatchRefreshPasswordRequest
1 |
|
UserPageQueryRequest
1 | import com.koohub.demo01.model.common.BasePageQuery; |
UserRequest
1 |
|
UserVO
1 |
|
订单业务
OrderRestController
1 |
|
OrderService
1 | public interface OrderService extends IService<OrderEntity> { |
OrderServiceImpl
1 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
OrderConvert
1 |
|
OrderMapper
1 |
|
OrderEntity
1 |
|
OrderRequest
1 |
|
UserOrderVO
1 |
|
相关测试类
UserEntityMapperTest
1 |
|
OrderEntityMapperTest
1 |
|
构建动态多数据源的应用
配置文件的变动
1 | # 删除原来 datasource 的相关配置,增加如下配置 |
相关配置类和组件
DruidConfig
1 | import com.alibaba.druid.pool.DruidDataSource; |
DruidProperties
1 | /** |
DynamicDataSource
1 | /** |
DynamicDataSourceContextHolder
1 | /** |
DataSourceType
1 | /** |
DataSource
1 | /** |
切面配置
增加依赖:
1 | <!--AOP--> |
DataSourceAspect
1 | /** |
相关业务类
DictController
1 |
|
DictService
1 | public interface DictService { |
DictServiceImpl
1 |
|
DictConvert
1 |
|
DictMapper
1 |
|