9D4.自动转换时间和语言
9D4.自动转换时间和语言
语言和时区的细致处理,是WingsBoot的重要特点,也是有别于其他框架的重要特征。
- 时间 - 可以系统级,线程级的调制时钟
- 时区 - 通过注解或类型,完成Dto/pojo的自动转换
- 语言 - MessageCode, EnumCode常量和强类型化,同时支持自动转换
时钟及时间线的调制
通常系统内有两种时钟,系统时钟和业务时钟,前者要求线性时间线,后者可能要求穿越。 尤其在测试,推演及复盘的时候,系统时钟也可能要调制到不同的时间线。
- mirana的
ThreadNow
和SlideDate
基础版时钟调制 - slardar的
Now
升级版的时钟调制,可调制用户时间线
因此,在编写程序时,若该功能需要调整时间线(建议全部业务代码)
Now.xxx()
代替Xxxx.now()
有slardar依赖时ThreadNow.xxx()
代替,无slardar依赖,但有mirana依赖
需要注意的是,业务的线程模型是否支持ThreadLocal的Inheritable。
- ThreadNow默认使用ThreadLocal
- Now默认使用TransmittableThreadLocal覆盖ThreadNow的默认值
关于ThreadNow.xxx()和Xxx.now()的jmh Benchmark 基本相同
Benchmark Mode Cnt Score Error Units
NowMain.now thrpt 6 11942.923 ± 368.430 ops/ms
NowMain.sys thrpt 6 12910.824 ± 226.997 ops/ms
时间和文字的I18n转换
WingsBoot的自动转换,依赖于两个Context获取ZoneId和Locale
- spring的
LocaleContextHolder
,Web层使用 - slardar的
TerminalContext
,推荐使用,尤其Service层
自动转换发生在SpringMvc的Request和Response,分别为
- Jackson的@RequestBody,@ResponseBody
- Spring的Data Binding,如@Param
手动转换通过AutoDtoHelper
进行,如Excel输出,但要避开自动转换。
- 默认仅对注解标记的字段生效,而自动转换可按类型处理
- 默认仅支持有getter的非final及transient字段
自动转换涉及的类型和配置项为
- LocaleDateTime - wings.slardar.datetime.datetime.auto=false
- ZonedDateTime - wings.slardar.datetime.zoned.auto=false
- OffsetDateTime - wings.slardar.datetime.offset.auto=true
- I18nString - 无配置,自动转换
自动及手工转换涉及的注解为
- AutoDtoAble - 标注容器类字段(仅手动转换)
- AutoI18nString - 标注String或I18nString类型
- AutoTimeZone - 标注Local/Zoned/Offset的DateTime
Context的规则和隐患
所有Context隐式传递变量,都是有副作用的,被视为反模式,要遵循规则,谨慎使用。 Wings中要避免函数具有副作用(SideEffect),但Context确实提供了便利,非常好用。
Context中经常使用ThreadLocal作为承载,而ThreadLocal必须要正确的set和remove。 要么在try{set}finally{remove}
,要么通过机制保证不会出现取值错误或内存泄露。
Wings以Transmittable-ThreadLocal作为基础, 尽可能使用TransmittableThreadLocal,并把Spring的Executor包装为TtlExecutors,保证正确传递Context。
在线程模型复杂的场景,一定要遵循Transmittable-ThreadLocal的原则和事项, 以正确处理Context,从而确保业务代码的正确性。
- TerminalContext - 由slardar的TerminalInterceptor处理
- Now - 按业务要求,需要自行
try{adjust()}finally{remove()}