本文介绍了12306项目中的组件库开发。
基础组件开发
如果说组件为业务代码提供提供了便捷,那么基础组件就是组件库的核心。
在framwork
中创建railway-base-spring-boot-starter
模块
全局变量
创建在所有模块都会用到的全局变量
全局过滤顺序
如果在不同的模块中创建过滤器顺序,可能会导致混乱。
封装spring IOC
有时我们需要在非spring管理的类下使用bean,所以我们需要在基础组件库中定义好这个功能,非spring管理的类使用bean。
注入属性
项目中是为了解决fastjson的autotype问题,开启安全模式而设置的属性注入类。初探fastJson的AutoType_fastjson autotype作用。
通过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事件。所以可以通过CAS或锁封装出一个我们自己的,能够保证只在初始化完成后发布一次的事件。springboot发布订阅机制。
一定要记得每个starter最后都要有自动配置文件
规约组件库
规约组件库相对好理解,在组件库中约定好状态码,异常,响应体,分页。这些需要约定的配置,防止模块之间不协调(如状态码不同一)。
其中对分页的封装可以看作防腐层,由于服务端使用mp,客户端可以不需要导入mp的分页就使用分页类,并且当服务端不再使用mp做分页时,可以做到客户端无感切换。
在分页中用到了泛型的函数式接口,见下面的文章:泛型和函数式接口。
用户组件库
我们将用户组件库外再套一层业务组件库,为未来可能有的其他业务如订单做准备。
在用户组件库中,定义了用户过滤器,如果HTTP Header中有userid这一项,我们就提取出在HTTP Header中的用户各种信息,放置到TTL中:transmittable-thread-local。同时封装了jwt的生成和解析操作。
很明显这个库的就是为了web领域而写的,所以在自动配置类上可以加入@ConditionalOnWebApplication
。
设计模式组件库
在本库中对多种设计模式进行抽象,使得业务场景可以公用,同时也起到了约束的作用。
构建者模式
责任链模式
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的幂等组件,幂等处理。