这几天在做一个缓存工具,其中一个目标是支持AOP,
于是有下面这样一段代码:
public class MethodCacheInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object value = CacheManager.getInstance().get(invocation.getArguments()); if(null == value) { value = invocation.proceed(); CacheManager.getInstance().put(invocation.getArguments(), value); } return value; } }
CacheManager是单例模式,方法的参数作为Key,方法的返回值作为Value。
所以,必须对Object以及Object[]进行序列化,so,采用Hessian、Kryo、Java等,可配置。
这篇文章,我们仅讨论Kryo。
接下来,我们先试用下Kryo,代码如下:
import java.io.ByteArrayOutputStream; import java.io.Serializable; import java.util.Arrays; // import org.junit.Test; // import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Output; import com.esotericsoftware.minlog.Log; // public class KryoTestByjjf { // @Test public void test() { Log.TRACE(); Kryo kryo = new Kryo(); // Output output = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); output = new Output(baos); kryo.writeClassAndObject(output, new EntityTest(23, "45")); output.flush(); byte[] b = baos.toByteArray(); // System.out.println(Hex.encodeHexStr(b, false)); //将byte数组转换为16进制 System.out.println(Arrays.toString(b)); } finally { if (output != null) output.close(); } } } // class EntityTest implements Serializable { // private int i; private String name; // public EntityTest() { } // public EntityTest(int i, String name) { this.i = i; this.name = name; } // public int getI() { return this.i; } // public String getName() { return this.name; } }
16进制输出为:0100636F6D2E6A6A662E456E74697479546573F4012E0134B5
如图所示:红色部分:未注册的类
蓝色部分:类名,其中最后一位xF4是被加上了x80的,so xF4=x80+x74,查询ASCII表,x74代表t
绿色部分:x2E代表23
黄色部分:x34代表4,xB5也是被加上x80了,xB5=x80+x35,查表,x35代表5
除了圈圈中的,还有两个x01,是IdentityObjectIntMap中存储的id
下面贴出序列化int、String的代码,一看便知。
public int writeVarInt (int value, boolean optimizePositive) throws KryoException { if (!optimizePositive) value = (value << 1) ^ (value >> 31); if (value >>> 7 == 0) { require(1); buffer[position++] = (byte)value; return 1; } if (value >>> 14 == 0) { require(2); buffer[position++] = (byte)((value & 0x7F) | 0x80); buffer[position++] = (byte)(value >>> 7); return 2; } if (value >>> 21 == 0) { require(3); buffer[position++] = (byte)((value & 0x7F) | 0x80); buffer[position++] = (byte)(value >>> 7 | 0x80); buffer[position++] = (byte)(value >>> 14); return 3; } if (value >>> 28 == 0) { require(4); buffer[position++] = (byte)((value & 0x7F) | 0x80); buffer[position++] = (byte)(value >>> 7 | 0x80); buffer[position++] = (byte)(value >>> 14 | 0x80); buffer[position++] = (byte)(value >>> 21); return 4; } require(5); buffer[position++] = (byte)((value & 0x7F) | 0x80); buffer[position++] = (byte)(value >>> 7 | 0x80); buffer[position++] = (byte)(value >>> 14 | 0x80); buffer[position++] = (byte)(value >>> 21 | 0x80); buffer[position++] = (byte)(value >>> 28); return 5; }
public void writeString (String value) throws KryoException { if (value == null) { writeByte(0x80); // 0 means null, bit 8 means UTF8. return; } int charCount = value.length(); if (charCount == 0) { writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8. return; } // Detect ASCII. boolean ascii = false; if (charCount > 1 && charCount < 64) { ascii = true; for (int i = 0; i < charCount; i++) { int c = value.charAt(i); if (c > 127) { ascii = false; break; } } } if (ascii) { if (capacity - position < charCount) writeAscii_slow(value, charCount); else { value.getBytes(0, charCount, buffer, position); position += charCount; } buffer[position - 1] |= 0x80; } else { writeUtf8Length(charCount + 1); int charIndex = 0; if (capacity - position >= charCount) { // Try to write 8 bit chars. byte[] buffer = this.buffer; int position = this.position; for (; charIndex < charCount; charIndex++) { int c = value.charAt(charIndex); if (c > 127) break; buffer[position++] = (byte)c; } this.position = position; } if (charIndex < charCount) writeString_slow(value, charCount, charIndex); } }