自定义头部 -->

如何编写一个 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这种方式集成,原因有以下几点:
  1. 相比 Mybatis + XML 配置项来说,Mybatis-Plus 增加了更多配置项,也因此我们无需在配置 mybatis-config.xml 配置文件

  2. Mybatis-Plus增加BaseMapper接口, 常规CRUD可以替我们自动生成

    • insert(DO do)
    • updateById(DO do)
    • deleteById(@Param("id") Integer id)
    • selectById(@Param("id") Integer id)
  3. 注解的方式不适合排版SQL, 且mapper接口很长显得杂乱

    Mybatis官方文档
    因为最初设计时,MyBatis 是一个 XML 驱动的框架.配置信息是基于 XML 的,而且映射语句也是定义在 XML 中的.而到了 MyBatis 3,就有新选择了.MyBatis 3 构建在全面且强大的基于 Java 语言的配置 API 之上.这个配置 API 是基于 XML 的 MyBatis 配置的基础,也是新的基于注解配置的基础.注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销.
    不幸的是,Java 注解的的表达力和灵活性十分有限.尽管很多时间都花在调查、设计和试验上,最强大的 MyBatis 映射并不能用注解来构建——并不是在开玩笑,的确是这样.比方说,C#属性就没有这些限制,因此 MyBatis.NET 将会比 XML 有更丰富的选择.也就是说,基于 Java 注解的配置离不开它的特性.
    他们自己也不推荐这种写法.

  4. tkmybatis 是多个开源项目组合起来的, tk是toolkit 的缩写.

建议

不要在 service 中使用 QueryWrapper 拼接动态条件, 这样业务逻辑层会充斥着各种查询,不方便做统一管理.

Mybatis-Plus

https://mp.baomidou.com/

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提问
    这期就这么多了.欢迎大家评论,交流,关注,点赞~
posted @ 2020-03-03 13:59  AllenAlan  阅读(603)  评论(0编辑  收藏  举报