本文介绍了12306项目中的组件库开发。

基础组件开发

如果说组件为业务代码提供提供了便捷,那么基础组件就是组件库的核心。

framwork中创建railway-base-spring-boot-starter 模块

全局变量

创建在所有模块都会用到的全局变量

全局过滤顺序

如果在不同的模块中创建过滤器顺序,可能会导致混乱。

封装spring IOC

有时我们需要在非spring管理的类下使用bean,所以我们需要在基础组件库中定义好这个功能,非spring管理的类使用bean

注入属性

项目中是为了解决fastjson的autotype问题,开启安全模式而设置的属性注入类。初探fastJson的AutoType_fastjson autotype作用open in new window

通过InitializingBean重写afterPropertiesSet,配合自动配置从而设置系统变量,开启安全模式。

public class FastJsonSafeMode implements InitializingBean {
    @Override
    public void afterPropertiesSet() {
        System.setProperty("fastjson2.parser.safeMode", "true");
    }
}
public class ApplicationBaseAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(value = "framework.fastjson.safa-mode", havingValue = "true")
    public FastJsonSafeMode railwayFastJsonSafeMode() {
        return new FastJsonSafeMode();
    }
}

单例容器

引入单例容器,防止一些无状态的对象重复创建,消耗系统性能。

  • 容器采用ConcurrentHashMap
  • 使用@NoArgsConstructor(access = AccessLevel.PRIVATE)生成私有无参构造
  • 采用函数式接口提供当get的key不存在时,由调用方决定提供对象。

安全初始化事件

在基础库中封装出一个基于发布订阅机制的,只在Spring Boot 应用程序准备就绪时触发的事件,以便于我们执行任务。看上去ApplicationReadyEvent是一个不错的选择,但是springboot启动时多次监听到ApplicationReadyEvent事件open in new window。所以可以通过CAS或锁封装出一个我们自己的,能够保证只在初始化完成后发布一次的事件。springboot发布订阅机制

一定要记得每个starter最后都要有自动配置文件

规约组件库

规约组件库相对好理解,在组件库中约定好状态码,异常,响应体,分页。这些需要约定的配置,防止模块之间不协调(如状态码不同一)。

其中对分页的封装可以看作防腐层,由于服务端使用mp,客户端可以不需要导入mp的分页就使用分页类,并且当服务端不再使用mp做分页时,可以做到客户端无感切换。

在分页中用到了泛型的函数式接口,见下面的文章:泛型和函数式接口

用户组件库

我们将用户组件库外再套一层业务组件库,为未来可能有的其他业务如订单做准备。

在用户组件库中,定义了用户过滤器,如果HTTP Header中有userid这一项,我们就提取出在HTTP Header中的用户各种信息,放置到TTL中:transmittable-thread-local。同时封装了jwt的生成和解析操作。

很明显这个库的就是为了web领域而写的,所以在自动配置类上可以加入@ConditionalOnWebApplication

设计模式组件库

在本库中对多种设计模式进行抽象,使得业务场景可以公用,同时也起到了约束的作用。

构建者模式

builder-构建者模式

责任链模式

chain-责任链模式。在项目中,使用HaspMap存放多个链条,用bean的type做key,标识不同的责任链,将一条链上的组件链接起来,使用Ordered来进行排序。采用CommandLineRunner在项目初始化完成之前,将责任链装配好。

策略模式

本项目对策略模式做了高度抽象,和责任链相同,使用map来存放多个不同领域的策略,采用base组件库中的安全初始化事件来装配。然后有两种方式选取相应的策略:

  • 根据mark来指定选择bean
  • 根据正则表达式模糊匹配mark来选择第一个匹配上的bean

公用组件库

提供了公用的一些工具类以及一些公共枚举,最重要的是扩展了快速消费线程池,创建了线程池的构建者模式,使用cglib动态代理扩展了线程池的拒绝策略。快速消费线程池

分布式id组件库

以雪花算法作为基本,结合基因算法,能够更好的分库分表。雪花算法

数据库组件库

引入了自定义的雪花生成器代替mybatis-plus的id生成器,引入了基础的实体类,配置了mp的自动填充,将自定义分页参数和mp的分页参数做了衔接,创建了PageUtil。同时有一个分库分表hash规则,目前没有学习分库分表,后续再补上。

日志组件库

通过自定义注解和aop,实现打印日志的功能。

web组件库

首先定义了全局返回对象,然后通过aop实现了全局异常处理,包括参数校验异常,应用异常,为捕获异常。

为了优化servlet的首次响应速度,使用CommandLineRunner在spring初始化时就发送一次请求。

缓存组件库

在本组件库中,抽象出来了通用的Cache接口,为以后的多级缓存留有扩展空间。定义了分布式缓存接口,实现了Redis缓存组件,采用静态代理对Redis的操作做了增强。其中涉及到了布隆过滤器,以及分布式锁,能够更大限度上的防止缓存击穿和缓存穿透。

幂等组件库

主要开发了基于parm、token、SpEL的幂等组件,幂等处理

上次更新:
Contributors: YangZhang