A2.米拉娜工具包
A2.米拉娜工具包
Mirana提供的工具类
A2.1.anti/
反工程化
- BeanVisitor - 反射遍历Bean的Field,主要用于属性格式化。
- G - 反模式,跨层传值
- L - 反模式,跨层收集信息
A2.2.best/
高质量代码
- AssertArgs - 前置断言 IllegalArgumentException或BadArgsException
- AssertMessage - 断言 MessageException
- AssertState - 中间或后置断言 IllegalStateException或BadStateException
- DummyBlock - 关闭安全代码块的IDEA警报,不可用代码块的标记
- Param - 注解param是否被修改
- TypedKey - 有类型的Map的Value注册
- TypedReg - 有类型的Map的Key和Value注册
A2.3.bits/
二进制,字节相关
- Aes - Aes128及Aes256公共类
- Aes128 - jdk AES/CBC/PKCS5Padding,若AES/CBC/PKCS7Padding,用bouncycastle
- Aes256 - jdk AES/CBC/PKCS5Padding,java1.8.0_162以上推荐使用
- Base64 - 默认使用 RFC4648_URLSAFE 和 UTF8。支持
+/
和-_
- Bytes - Hex和unicode(
我
(25105)=>'\u6211') - HmacHelp - MessageAuthenticationCode HmacMD5, HmacSHA1, HmacSHA256
- Md5 - md5sum, md5check
- HdHelp - MessageDigest MD5, SHA1, SHA256
A2.4.cast/
类型转换
- BiConvertor - 双向converter
- BoxedCastUtil - 包装类和原始类型的转换
- BoxedTypeUtil - 包装类兼容的instanceOf,isAssignable
- EnumConvertor - 支持enum全路径模糊序列化和具名精确序列化
- MethodConvertor - 精简的Method的序列化
- StringCastUtil - 字符串和其他类型的转换
- TypedCastUtil - 类型参数,泛型的转换
A2.5.code/
编码转码
5a.Crc4Int - 带crc的int32
根据int数值,生成一个伪随机,可校验的,可解密出原值的int数字。 尽量提高人类可读性和伪随机性。
5b.Crc8Long, Crc8LongUtil - 带crc的int64
根据long数值,生成一个伪随机,可校验的,可解密出原值的long数字。 用户可以自定义bit位序列,系统默认提供三种,参考Crc8LongUtil。
适用场景,安全要求一般,暴露的数字ID信息。可以高效的双向解析和校验。
5c.Excel26Az - excel的26进制索引
按Excel列命名方式进行双向解析(A:1,B:2,...,Z:26,AA:27)
5d.LeapCode - 伪随机高可读code
提供26字母和10数字(去掉UOIL易混淆)的构成的32位字母数字编码。 编码后的字符串看起来比较随机,可解密出原值,可填充到固定长度。 用户可以自定义数字字典,以实现比较安全的效果。
参考 https://www.crockford.com/base32.html
适用场景,伪随机验证码,安全要求一般,高效双向解析的编码。
5e.其他编码
- Mod10Code - usps 的校验算法
- RandCode - 基于Random的一些人类可读性更好的随机数
- SlotCode - 固定仓位的随机分配,比如取件码
A2.6. cond/
条件断言
- EqualsUtil - 等值判断
- StaticFlag - 全局Flag
- IfSetter - 条件设置工具
A2.7.data/
数据传递
- Arr - 一些Array的操作
- CodeEnum - 业务code枚举,如多国语,状态
- DataResult - 携带data的DTO
- Diff - diff2个集合,如数据集中判断插入,更新,删除
- Null - 以
空
消除null是我们的目标。 - Q - 单参数Query类
- R - Result的场景类
- Rank - 按多条件顺序来排序
- U - 内部传递数据的Tuple,Either
- Z - 第一个满足条件(如非null)的数据操作
A2.8.dync/
动态编译
- Java - 动态编译和创建java
- OrderedSpi - 根据顺序获取第一个SPI
A2.9.evil
谨慎使用
- Attention - 被标记的方法应该遵循固定模式,避免误用
- StartStageAttention - 启动阶段调用的方法,勿频繁使用
- ThreadLocalAttention - 注意ThreadLocal模式
- ThreadLocalProvider - 通过SPI获取ThreadLocal
- ThreadLocalSoft - SoftReference的ThreadLocal
- TweakingContext - 用来调试的上下文配置
A2.A.fake/
伪装数据
- FakeDate - 生成指定偏移量附近的伪随机日期,保证结果的幂等性。
- FakeName - 生成随机中文姓名
A2.B.flow/
流程控制
在高层架构设计,高阶函数调用,流处理中,需要使用异常参与流程中断。 类似spring security体系,scala的break语法,kotlin的return@
。 以下为低消耗的无栈异常,中断流程的场景,属反模式,若非必须不建议使用。
- FlowBreak - 静态工具类
- FlowBreakException - 用Enum类的异常参与控制流程。
- FlowEnum - 流程控制enum
- FlowReturnException - 具有返回值
- ReturnOrException - 是破例返回还是异常
A2.C.func/
function构造
- Clz - Class工具类
- Dcl - DCL of Runnable
- Fn - distinct和duplicate
- Lam - 通过lambda获取对象及方法的引用
A2.D.i18n/
多国语
- I18nAware - 标记型接口
- I18nEnum - 为普通enum的提供i18n能力
- I18nString - 支持 i18n的String
- LocaleResolver - 支持
-
和_
- ZoneIdResolver - 不区分大小写,支持部分命名
A2.E.id/
主键
e1.LightId - 轻量级分布式主键
轻量级分布式主键,采用双缓冲机制,使用sequence高效生成64bit数字主键。 ID能保证严格的单调递增
(升序),但不保证连续,其long型的64bit构成如下。
- long =
1-bit:0固定
+8-bit:验证
+1-bit:布局
+54-bit:序列
0固定
,保证ID为非负数。验证
,默认为0
填充,用Crc8Long生成构造伪随机数。布局
,提供全序列
和区序列
两种布局。全序列
=1bit(0)
+sequence(54bit)
区序列
=1bit(1)
+block(9bit)
+sequence(45bit)
序列
,依赖于布局,以下是其约束区块
=block(9bit=512)
,用来区分不同的主键生产中心。序号
=sequence(45bit|54bit)
,区块
内唯一递增序号。区块
的区间为[1,512]
,0
表示全序列
因为有效位只有55bit,所以存在以下特点。
- 生产中心,最多512个。通常一个数据中心,有一个生产中心。
- 若每秒消费5万ID,能连续22年,(2^45 -1)/(365x24x3600x50000)=22.3
- 如为最大序列布局,则在上诉能力上,增加512倍。
- sequence和时间无关,所以并发上限和使用年限,只根ID消费者能力有关。
- sequence和进程无关,所以能以key-value形式,产生不同类别的ID。
系统提供默认的双缓冲实现,在Loader
保证唯一升序的情况下,能够。
- 保证全局block-name生成唯一id。
- 线程内id升序,不同线程无法保证升序。
- 当id剩余不足某值(80%)时,异步补充id,无锁(非读写锁)
- 切换id段时,保证最小同步段,控制保护资源的范围。
- 根据id的每秒消耗数动态调节请求数量,预留60秒的使用量。
- 当缓冲id完全耗尽时,保证只有一个加载,其他等候成功或超时。
- 支持手动进行预加载(preload)所有可用id。
- 支持手动或定时清除错误。
- 支持手动调整运行时参数。
e2.LightIdBufferedProvider - 高性能,轻量级锁,双缓冲
轻量级锁,高性能,双缓冲 light-id 提供者。
实测性能,高于busy-wait+读写锁或大粒度的组合锁或同步块。 效能瓶颈在loader的io上,需要根据消耗量,优化maxCount。
共存在以下3类线程,且读线程会升级为写线程,甚至加载线程。 同一时刻,有多个读线程,但只有唯一写线程,唯一的加载线程。
- 读线程,正常的light-id调用者
- 写线程,读线程升级或加载线程,为buffer追加片段(segment)
- 加载线程,异步线程或读线程升级,通过loader加载segment
双缓冲的运行机制如下,会跟进id的使用量,自动控制预加载量,但不超过maxCount。
- 当Id余量低于20%时,唯一异步预加载
60s内最大使用量
或maxCount
- 当Id余量用尽时,读线程升级为写线程,其他读线程等待,直到被唤醒或超时
- 当读线程升级写线程时,存在loader,此读线程自旋忙等后,切换buffer。
e3.LightIdUtil - 对lightId特征long操作
对 lightId,long和sequence进行验证,转换的工具类。 可能够全局改变LightId中序列的默认布局及其顺序。
- forceBlockBit - 调整
区块
的bit数 - forceBlockFirst - 使用先
区块
布局,还是先序号
布局
e4.Ulid - 简单的ULID实现
仅快速生成ULID,不支持验证及解析。用于有序随机数,全局ID等。
A2.F.img/
图片
- ImageIoFix - problem-using-imageio-write-jpg-file
- StreamJpg - BufferedImage 写入
- Watermark - 水印
- ZoomRotateCrop - 缩放旋转剪切
A2.G.io/
IO及fs操作
- CircleInputStream - 可循环读取的流
- CompatibleObjectStream - 当serialVersionUID不兼容时,采用本地Class反序列化
- DirHasher - 本地文件系统不可保存太多文件
- Exec - 单线程同步执行,高级功能用Apache Commons Exec
- InputStreams - 不使用
commons-*
的补位 - NonCloseStream - 屏蔽掉close的流
- Zipper - 递归zip/unzip
A2.H.jaxb/
xml
注意,jaxb以在Java11中移除,故需要单独依赖。
- StringMapXmlWriter - 只把顶层元素变成key-value的map,用来做参数签名
A2.I.lock/
锁
- GlobalLock - 全局锁接口
- JvmStaticGlobalLock - 基于WeakReference的Jvm全局锁
A2.J.math/
行业中的数学算法
- AnyIntegerUtil - int,long,Number,String间的恩怨
- AverageDecimal - 平均数 20/6=
[3.33, 3.33, 3.34, 3.33, 3.33, 3.34]
- BalanceDecimal - 平衡数, 按权重分割数值
- BigDecimalUtil -
null
友好的的Decimal运算工具 - ComparableUtil -
null
不参与比较的比较器 - RatioNumber - 比例数,物品消耗的换算表示法。
A2.K.netx/
网络通讯
- SslTrustAll - 信任所以证书,使爬虫不报错
- SslVersion - jdk-8-will-use-tls-12-as-default
A2.L.page/
分页功能
- PageQuery - 分页查询
- PageResult - 分页结果
- PageUtil - 分页工具,使用
-1+1
算法,不是if-else
A2.M.pain/
异常痛苦
- BadArgsException - 多国语和枚举版的可无堆栈的IllegalArgumentException
- BadStateException - 多国语和枚举版的可无堆栈的IllegalStateException
- CodeException - 多国语和枚举版的可无堆栈的RuntimeException
- DebugException - 测试及调试跟踪专用
- HttpStatusException - 提供HttpStatus的无堆栈异常
- IllegalRequestException - 不合法的请求
- IllegalResponseException - 因状态问题无法正常响应
- IORuntimeException - Runtime版IOException
- MessageException - 默认无堆栈消息异常
- NoStackRuntimeException - 无需填充堆栈的异常,用于性能优先场景,堆栈无用的场景
- ThrowableUtil - Throwable堆栈和cause工具
- TimeoutRuntimeException - Runtime版TimeoutException
- UncheckedException - 包装受检异常为RuntimeException
- WaitingTimeoutException - 无栈的等待超时异常
A2.N.stat/
统计与监控
- GitStat - 对git提交按日期作者统计,或在mysql建表保存
- JvmStat - 返回当前jvm的Cpu,Mem,Thread信息
- LogStat - 对日志增长,关键词进行收集
A2.O.text/
全半角,白字符,格式化工具
- BarString - 构造Bar分隔的字符串,自动调整Bar字符。
- BuilderHelper - null友好碎片少的StringBuilder操作
- BuilderHolder - 减少碎片的StringBuilder
- CaseSwitcher - camel,snake,pascal,kebab命名转换
- FormatUtil - printf的
%
;logbak的{}
;message的{0}
,参数填充 - FullCharUtil - 全角字符工具
- HalfCharUtil - 半角字符工具
- JsonTemplate - 构造Json的模板
- StringTemplate - 字符串模板,免替换尴尬,可读性好,性能优
- WhiteUtil - 弥补java trim的不足,更多Whitespace处理
- Wildcard - 快速的通配符匹配,仅支持
?
和*
A2.P.time/
时间日期
- DateFormatter - 线程安全的,比正常formatter要快
- DateLocaling - LocalDateTime和时区的故事
- DateNumber - 日期转化成数字的双向转化
- DateParser - 更高效兼容的解析日期数字的字符串
- Sleep - Thread.sleep的一点包装
- SlideDate - 包装了OffsetClock的会计日期工具
- StopWatch - 对代码进行计时跟踪的秒表
- ThreadNow - 提供线程级的调准时钟
A2.Q.tk
token和ticket
用于私钥凭证,需要中心控制又去中心的凭证,在无意义session和庞大jwt体系之间的场景。 session的replication和sticky在水平扩展上十分稳定成熟,如redis和Hazelcast。 JsonWeb系列体系强大,多在数据交换且安全要求较高的场景,凭证领域也是新杀出的战场。
应用场景是RememberMe或读取异步任务结果的凭证。
在RememberMe中,biz-data可包括uid,而sig-data中,需要把用户密码和盐追加进行验签。 当用户再次登录,密码修改,或凭证过期时,都可以对ticket的有效性进行判断。
q1.Ticket - 有中心权力的去中心凭证
特点是短小,可过期,可踢人,可验签,有一定业务意义,代替无意义的随机token。
其中,Data后缀为业务语义,Part后缀为传输语义,不同视角的布局为,
- 业务布局:SigData +
~
+ SigPart - SigData = PubPart + (
~
+ BizData)? - PubPart =
mod
+-
+due
+-
+seq
- BizData: 业务数据,如明文的Json
- 传输布局:PubPart +
~
+ SecPart - SecPart = (BizPart +
~
)? + SigPart - BizPart: 加密后的BizData
- SigPart: 签名数据,对SigData数据签名
mod
: 约定模式,加密及签名,BizPart类型等,用于反序列化。英数due
: 有效期,从1970-01-01起的秒数,用于判断时间过期。正整数seq
: 签发序号,用于判定新旧,业务过期,正整数salt
- 加密或签名秘钥,如加盐
,对称秘钥,非对称私钥。
公开部分对应的业务场景和说明如下,
mod
服务端或同用户协商制定,包括加密和签名算法,数据格式,用户字段等,如内定。- any = 仅原文解析和合并各个字段。
- am0 = aes256(biz-data, salt) + md5(sig-data) 无盐Md5
- am1 = aes256(biz-data, salt) + md5(sig-data + salt) 加盐Md5
- ah1 = aes256(biz-data, salt) + HmacSha1(sig-data, salt) Hmac验签
- ah2 = aes256(biz-data, salt) + HmacSha256(sig-data, salt) Hmac验签
due
凭证过期的秒数,从1970-01-01起的秒数
,不是毫秒。- 到期凭证,client需要到服务器续签。
- 服务器端自行确定行为,如续签,拒绝,重发等。
seq
签发序号,生成凭证时递增,续签时不变,seq不同时,须重新获得凭证。- 当用户登录时,生成凭证,其他端再次登录时,seq增加,则可踢出旧凭证。
- 当凭证过期时,未发生再次登录,可以同seq续签新凭证。
- 0 表示无需验证序号,一般用于弱权限场合,如临时凭证
凭证,可以在http的header,session和url-string中传递。
- 无私钥者,无法验签和解密,仅可以使用PubPart信息。
- 有私钥者,通过验签和解密,判断凭证有效性,获取业务内容。
- 无私钥者,且需要验签的情况,可不加盐,不用hmac签名
q2.默认的基本实现和工具类
AnyTicket
- 可以解析任何mod的ticketTicketHelp
- 提供了ticket解析,验签的基本工具类