先是申明了局部变量b(用来存储需要放入memcached服务器的字节数组)及flags(用来存储标志信息)。然后依次判断对象o是否字符串类型、长整型类型等,并将对象o编码成相应的字节数组存放在局部变量b中。
特别注意第57行,当o的类型不是字符串、基本类型的包装类型及byte[]数组时,会调用BaseSerializingTranscoder.serialize()方法,该方法源代码如下:
protected byte[] serialize(Object o) { if (o == null) { throw new NullPointerException("Can't serialize null"); } byte[] rv = null; try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(bos); os.writeObject(o); os.close(); bos.close(); rv = bos.toByteArray(); } catch (IOException e) { throw new IllegalArgumentException("Non-serializable object", e); } return rv; }很明显,该方法就是进行对象序列化,将Java对象转化成byte数组并返回。相信大家看到这里,应该明白了为什么自定义对象需要实现Serializable接口才能保存进Memcached中。如果数据对象没有实现Serializable接口,那么在进行对象序列化时,将会抛出IOException,最终抛出IllegalArgumentException,并提示Non-serializable object。
另着重说明下CachedData类的作用,该类封装了cas值(该值用来实现原子更新,即客户端每次发出更新请求时,请求信息中都会附带该cas值,memcached服务端在收到请求后,会将该cas值与服务器中存储数据的cas值对比,如果相等,则用新的数据覆盖老的数据;否则,更新失败。在并发环境下特别有用)、data数据(即要缓存的数据值或者获取到的缓存数据,以byte[]数组形式存储),flag信息(标识byte[]数组额外数据类型信息及byte[]数组是否进行过压缩等信息,用一个int类型存储)及其它信息。
set源码分析到这里,下面说下get源码。
2.get同样的,先列出get方法大概的源码调用过程如下:
XMemcachedClient.get() XMemcachedClient.fetch0() XMemcachedClient.sendCommand() MemcachedConnector.send() AbstractSession.write() MemcachedTCPSession.wrapMessage() TextGetCommand.encode() SerializingTranscoder.decode() SerializingTranscoder.decode0() BaseSerializingTranscoder.deserialize()先是调用XMemcacheClient.get(final String key)方法,key形参对应字符串“key"。从该方法一直到TextGetCommand.encode()调用,可以看作是组装get命令并发送到服务器过程,在收到服务器响应消息后,将响应消息组装成CachedData,并调用SerializingTranscoder.decode(CachedData d)方法,即进行字节流解码工作。该方法代码如下:
public final Object decode(CachedData d) { byte[] data = d.getData(); int flags = d.getFlag(); if ((flags & COMPRESSED) != 0) { data = decompress(d.getData()); } flags = flags & SPECIAL_MASK; return decode0(d,data, flags); }先是获取字节数组及标志信息,根据标志位决定是否要解压缩字节数组。最后调用decode0(CachedData cachedData,byte[] data, int flags)方法,代码如下:
protected final Object decode0(CachedData cachedData,byte[] data, int flags) { Object rv = null; if ((cachedData.getFlag() & SERIALIZED) != 0 && data != null) { rv = deserialize(data); } else { if (this.primitiveAsString) { if (flags == 0) { return decodeString(data); } } if (flags != 0 && data != null) { switch (flags) { case SPECIAL_BOOLEAN: rv = Boolean.valueOf(this.transcoderUtils .decodeBoolean(data)); break; case SPECIAL_INT: rv = Integer.valueOf(this.transcoderUtils.decodeInt(data)); break; case SPECIAL_LONG: rv = Long.valueOf(this.transcoderUtils.decodeLong(data)); break; case SPECIAL_BYTE: rv = Byte.valueOf(this.transcoderUtils.decodeByte(data)); break; case SPECIAL_FLOAT: rv = new Float(Float.intBitsToFloat(this.transcoderUtils .decodeInt(data))); break; case SPECIAL_DOUBLE: rv = new Double(Double .longBitsToDouble(this.transcoderUtils .decodeLong(data))); break; case SPECIAL_DATE: rv = new Date(this.transcoderUtils.decodeLong(data)); break; case SPECIAL_BYTEARRAY: rv = data; break; default: log .warn(String.format("Undecodeable with flags %x", flags)); } } else { rv = decodeString(data); } } return rv; }