如何编写一个 Spring Boot微服务节点?
随手写个 Spring Boot微服务节点
当年前圈内各路神仙开始实践服务拆分,开始做SOA, 6年前兴起的微服务,近几年火热的SpringCloud, 最近边车模式开始流行ServiceMesh服务网格.微服务在我们面前反复横跳, 顺手耗掉你几根头毛的同时不说吸还吸粉无数.今天我卢本伟随手写个微服务节点不是问题.
构建Spring Boot maven多模块项目
使用IDEA构建多模块maven 项目骨架, 基本操作不多bb.
Spring Boot 版本选择2.2.4
- 打开idea选择new project选择Spring Initializr 创建第一个Springboot项目
- 保留以下文件,其他文件都删除
- 构建maven子模块
- 将多余文件删除, 将pom中
修改为如下所示 - web模块在构造的时候重复上面的步骤, 并勾选Spring Web选项
模块功能
demo
|-- demo-api jar文件 API二方包
|-- demo-core jar文件 核心业务层
|-- demo-data jar文件 持久层
|-- demo-server jar文件 provider,发布的web服务
|-- demo-util jar文件 工具包
`-- pom.xml maven 发布文件
集成ORM框架Mybatis
集成方案
目前我知道的有四种方式:
- Mybatis + XML
- Mybatis + 注解
- Mybatis-Plus
- tkmybatis
这里我们选用Mybatis-Plus这种方式集成,原因有以下几点:
-
相比 Mybatis + XML 配置项来说,Mybatis-Plus 增加了更多配置项,也因此我们无需在配置 mybatis-config.xml 配置文件
-
Mybatis-Plus增加BaseMapper接口, 常规CRUD可以替我们自动生成
- insert(DO do)
- updateById(DO do)
- deleteById(@Param("id") Integer id)
- selectById(@Param("id") Integer id)
-
注解的方式不适合排版SQL, 且mapper接口很长显得杂乱
Mybatis官方文档
因为最初设计时,MyBatis 是一个 XML 驱动的框架.配置信息是基于 XML 的,而且映射语句也是定义在 XML 中的.而到了 MyBatis 3,就有新选择了.MyBatis 3 构建在全面且强大的基于 Java 语言的配置 API 之上.这个配置 API 是基于 XML 的 MyBatis 配置的基础,也是新的基于注解配置的基础.注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销.
不幸的是,Java 注解的的表达力和灵活性十分有限.尽管很多时间都花在调查、设计和试验上,最强大的 MyBatis 映射并不能用注解来构建——并不是在开玩笑,的确是这样.比方说,C#属性就没有这些限制,因此 MyBatis.NET 将会比 XML 有更丰富的选择.也就是说,基于 Java 注解的配置离不开它的特性.
他们自己也不推荐这种写法. -
tkmybatis 是多个开源项目组合起来的, tk是toolkit 的缩写.
建议
不要在 service 中使用 QueryWrapper 拼接动态条件, 这样业务逻辑层会充斥着各种查询,不方便做统一管理.
Mybatis-Plus
maven配置
<!--全局变量-->
<properties>
<mysql.version>5.1.48</mysql.version>
<mybatis.plus.version>3.2.0</mybatis.plus.version>
<pagehelper.version>1.2.13</pagehelper.version>
</properties>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- orm mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>${mybatis.plus.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.version}</version>
</dependency>
Mybatis-Plus配置
@Configuration
@MapperScan(basePackages = "com.barm.demo.data.*")
public class MybatisPlusConfig {
}
application.yaml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag
id-type: auto
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.barm.demo.domain
logging:
level:
cn:
iocoder:
springboot:
lab12:
mybatis:
mapper: debug
其他
更多配置项,参考 MyBatis-Plus 使用配置
IDEA插件
看到这里有的观众老爷可能会问为“为啥没MybatisGenerate模块?”, 这里我们推荐使用MyBatisCodeHelper-Pro, Intellij下Mybatis插件.一个不错的生产力工具.
放上几个操作感受一下.
- 根据DO生成DDL
- 生成Mapper
- 添加属性重复上面操作可直接修改原文件
- 根据方法生成Mapper接口及xml,命名当时类似JPA
- 从Mapper中生成对应Service方法实现
- 生成service分页方法,这里使用的是google的PageHelper
这个插件是收费的, 但是依然提供了很多免费功能, 可体验一个月.有兴趣的小伙伴可以试试.
抽象出全局common包
用于统一服务之间的交互格式,和一些常用的工具类
github源码地址: https://github.com/allennotes/common
maven 配置
<properties>
<common.version>1.0.0SNAPSHOT</common.version>
</properties>
<dependency>
<groupId>com.barm</groupId> <artifactId>common</artifactId>
<version>${common.version}</version>
</dependency>
异常统一处理
- 定义公用系统异常
@Getter
public class ApplicationException extends Exception{
/** 结果枚举*/
private final ResultEnum resultEnum;
/** 自定义异常信息*/
private String errMsg;
/** 异常码 */
private Integer errCode;
public ApplicationException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.errCode = resultEnum.getCode();
this.errMsg = resultEnum.getMsg();
this.resultEnum = resultEnum;
}
public ApplicationException(String errMsg) {
super(ResultEnum.FAIL.getMsg());
this.errCode = ResultEnum.FAIL.getCode();
this.errMsg = errMsg;
this.resultEnum = ResultEnum.FAIL;
}
}
- 如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice
@Slf4j
@RestControllerAdvice
public class ExceptionHandlers {
@ExceptionHandler(value = ApplicationException.class)
public ResultVO applicationException(ApplicationException e){
log.error("exception for system", e);
return new ResultVO(ResultEnum.FAIL);
}
@ExceptionHandler(value = RuntimeException.class)
public ResultVO runtimeException(RuntimeException e){
log.error("exception for runtime", e);
ResultVO resultVO = new ResultVO(ResultEnum.FAIL);
return resultVO;
}
}
基于线程池的异步注解
从Spring3开始提供了@Async注解,这里我们无需引入直接上配置.
@EnableAsync
@Configuration
public class AsyncConfig {
private static final int corePoolSize = 10;
private static final int maxPoolSize = 50;
private static final int keepAliveTime = 10;
private static final int queueCapacity = 100000;
private static final String threadNamePrefix = "Async-Executor-";
@Bean
public ThreadPoolTaskExecutor getAsyncExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
对象转化
DO,BO,VO各模块之间的转换, 我们使用mapstruct,请参考属性拷贝你还在用BeanUtils?
启动项目
总结
- 本文主要讲述了使用Spring Boot 快速构建一个微服务节点主要功能
-
- 后续会陆续更新新的功能,例如:
- 更多github源码:https://github.com/allennotes/webserver
- 欢迎issues提问
这期就这么多了.欢迎大家评论,交流,关注,点赞~