我正在编写一个消息传递门面,它接收任意 POJO 并以 JSON 格式通过网络发送它们,工作流程如下:
- 用户调用
MessagingFacade.sendMessage(Object)
- 从池中借用一个 ByteBuffer,我们将把消息序列化到这个缓冲区中
- 通过调用将 POJO 转换为 JSON
JsonSerializer.serialize(Object, ByteBuffer)
- 通过网络发送已编码的消息
Transport.send(ByteBuffer)
,保留对将在消息发送时通知的承诺的引用 - 将回调附加到 Promise 以在 ByteBuffer 被写入线路后将其返回到池中
- 从
MessagingFacade.sendMessage(Object)
调用返回
这是池化 ByteBuffers 的一个相对简单的用例,因为我们可以调用clear()
以在对象返回池时重置状态。
我没有编写自己的对象池,而是尝试利用 Apache 中已经提供的对象池commons-pool
。然而,似乎有一个相当大的警告GenericObjectPool
和SoftReferenceObjectPool
......
在借用/归还对象时,这两个池使用hashCode()
和/或equals()
来标识关联的PooledObject<ByteBuffer>
. ByteBuffer
鉴于equals()
和hashCode()
实现涉及评估底层byte
数组的内容,这对 有非常实际的影响:
- 对象清理 - 当对象
ByteBuffer
返回池时,它的状态为“已清理”。这仅涉及调用ByteBuffer.clear()
. 这不会将数组中的所有字节清零,这意味着返回 ,equals()
与借用时会hashCode()
给出不同的结果。ByteBuffer
- 评估速度 - 鉴于我正在
ByteBuffer
以最大消息大小 (1MB) 的容量汇集实例,评估两者hashCode()
并且equals()
必须线性遍历这个非常大的数组
Apache commons-pool 实现似乎不适合任何用例,其中(a)该类具有昂贵的equals()
实现hashCode()
或(b)hashCode()
在清理后不会产生稳定的结果。
GenericObjectPool
为这个用例制作或工作的唯一可行选择SoftReferenceObjectPool
似乎是将其包装ByteBuffer
在另一个使用身份相等/哈希码逻辑的类中。
这是可行的,但考虑到这个用例的普通程度,感觉有点麻烦。这种方法有更好的选择吗?
最后一点;由于 和 的不稳定性,equals()
实际上hashCode()
会从 中获得异常GenericObjectPool
,因为池认为您正在尝试返回一个从未从池中借来的对象:
java.lang.IllegalStateException: Returned object not currently part of this pool
at org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java:537)
...