4.7. 数据编码
编码是在存储数据前由数据进行的数据转换操作,以及从存储中读取数据时进行的数据转换操作。
4.7.1. 概述 复制链接链接已复制到粘贴板!
编码允许在 API 调用(map、监听器、流等)期间处理某些数据格式,而有效存储的格式会有所不同。
数据转换由 org.infinispan.commons.dataconversion.Encoder 的实例处理:
public interface Encoder {
/**
* Convert data in the read/write format to the storage format.
*
* @param content data to be converted, never null.
* @return Object in the storage format.
*/
Object toStorage(Object content);
/**
* Convert from storage format to the read/write format.
*
* @param content data as stored in the cache, never null.
* @return data in the read/write format
*/
Object fromStorage(Object content);
/**
* Returns the {@link MediaType} produced by this encoder or null if the storage format is not known.
*/
MediaType getStorageFormat();
}
4.7.2. 默认编码器 复制链接链接已复制到粘贴板!
根据缓存配置,Data Grid 会自动选择 Encoder。下表显示了哪些内部 Encoder 用于以下配置:
| 模式 | 配置 | encoder | 描述 |
|---|---|---|---|
| embedded/Server | Default(默认) | IdentityEncoder | passthrough encoder,没有进行转换 |
| embedded | StorageType.OFF_HEAP | GlobalMarshallerEncoder | 使用 Data Grid internal marshaller 转换为 byte[].可以委托到缓存管理器中配置的 marshaller。 |
| embedded | StorageType.BINARY | BinaryEncoder | 使用 Data Grid internal marshaller 转换为 byte[],但 primitives 和 String 除外。 |
| 服务器 | StorageType.OFF_HEAP | IdentityEncoder | 远程客户端接收的字节[] |
4.7.3. 以编程方式覆盖 复制链接链接已复制到粘贴板!
可以通过调用 AdvancedCache 中的 .withEncoding () 方法变体来覆盖用于键和值的编程编码。
示例,请考虑以下缓存配置为 OFF_HEAP:
// Read and write POJO, storage will be byte[] since for
// OFF_HEAP the GlobalMarshallerEncoder is used internally:
cache.put(1, new Pojo())
Pojo value = cache.get(1)
// Get the content in its stored format by overriding
// the internal encoder with a no-op encoder (IdentityEncoder)
Cache<?,?> rawContent = cache.getAdvancedCache().withEncoding(IdentityEncoder.class);
byte[] marshalled = (byte[]) rawContent.get(1);
如果缓存中的任何操作都不需要解码,如计算条目数,或者计算 OFF_HEAP 缓存的 byte[] 的大小,则覆盖非常有用。
4.7.4. 定义自定义 Encoders 复制链接链接已复制到粘贴板!
自定义编码器可以在 EncoderRegistry 中注册。
在启动缓存前,请确保在集群的每个节点中完成注册。
考虑使用 gzip 压缩/解压缩的自定义编码器:
public class GzipEncoder implements Encoder {
@Override
public Object toStorage(Object content) {
assert content instanceof String;
return compress(content.toString());
}
@Override
public Object fromStorage(Object content) {
assert content instanceof byte[];
return decompress((byte[]) content);
}
private byte[] compress(String str) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gis = new GZIPOutputStream(baos)) {
gis.write(str.getBytes("UTF-8"));
gis.close();
return baos.toByteArray();
} catch (IOException e) {
throw new RuntimeException("Unabled to compress", e);
}
}
private String decompress(byte[] compressed) {
try (GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(compressed));
BufferedReader bf = new BufferedReader(new InputStreamReader(gis, "UTF-8"))) {
StringBuilder result = new StringBuilder();
String line;
while ((line = bf.readLine()) != null) {
result.append(line);
}
return result.toString();
} catch (IOException e) {
throw new RuntimeException("Unable to decompress", e);
}
}
@Override
public MediaType getStorageFormat() {
return MediaType.parse("application/gzip");
}
@Override
public boolean isStorageFormatFilterable() {
return false;
}
@Override
public short id() {
return 10000;
}
}
它可以通过以下方法注册:
GlobalComponentRegistry registry = cacheManager.getGlobalComponentRegistry();
EncoderRegistry encoderRegistry = registry.getComponent(EncoderRegistry.class);
encoderRegistry.registerEncoder(new GzipEncoder());
然后用于从缓存中写入和读取数据:
AdvancedCache<String, String> cache = ...
// Decorate cache with the newly registered encoder, without encoding keys (IdentityEncoder)
// but compressing values
AdvancedCache<String, String> compressingCache = (AdvancedCache<String, String>) cache.withEncoding(IdentityEncoder.class, GzipEncoder.class);
// All values will be stored compressed...
compressingCache.put("297931749", "0412c789a37f5086f743255cfa693dd5");
// ... but API calls deals with String
String stringValue = compressingCache.get("297931749");
// Bypassing the value encoder to obtain the value as it is stored
Object value = compressingCache.withEncoding(IdentityEncoder.class).get("297931749");
// value is a byte[] which is the compressed value