BinaryOutputArchive类位于org.apache.jute包中,是序列化组件中的一个类。从字面意思理解就是输出类。这里类实现了OutputArchive接口。并且在构造函数中需要传递一个DataOutput接口的实现类。
在这个代码中有一段代码引起了我的注意:
/** * create our own char encoder to utf8. This is faster * then string.getbytes(UTF8). * @param s the string to encode into utf8 * @return utf8 byte sequence. */ final private ByteBuffer stringToByteBuffer(CharSequence s) { bb.clear(); final int len = s.length(); for (int i = 0; i < len; i++) { if (bb.remaining() < 3) { ByteBuffer n = ByteBuffer.allocate(bb.capacity() << 1); bb.flip(); n.put(bb); bb = n; } char c = s.charAt(i); //一个字节 if (c < 0x80) { bb.put((byte) c); } else if (c < 0x800) { bb.put((byte) (0xc0 | (c >> 6))); bb.put((byte) (0x80 | (c & 0x3f))); } else { bb.put((byte) (0xe0 | (c >> 12))); bb.put((byte) (0x80 | ((c >> 6) & 0x3f))); bb.put((byte) (0x80 | (c & 0x3f))); } } bb.flip(); return bb; }
根据代码的注释说这里的实现比java自身的要高效。那么究竟是怎么样呢?值得对比进行学习一番。
首先在对比之前要先弄清除他们在做什么。这里的方式实现了一个字符串转化正一个utf-8编码格式的字节数组。那么utf-8编码格式是规定怎么进行转换的呢?大体的规则如下:
1.对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2.对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
实例如下:
一个字节 0000 0000-0000 007F | 0xxxxxxx
两个字节 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
三个字节 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
四个字节 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
根据上面的规则再去理解代码就方便一些了。stringToByteBuffer方法的逻辑大致是:
-
循环字符的长度。如果缓冲字节类ByteBuffer 的剩余空间不足则扩充1倍。(这里使用了位运算)
-
如果是1个字节直接保存
-
如果是2个字节,先把字符的前一部分根据规则放入第一个字节中,然后把后面一部分放入第二个字节中。0xc0-->11000000。用它或一个字符刚好满足上面规则中110xxxxx的要求。代码 c >> 6 让我理解了好半天(可能是我比较笨的原因吧)。最后我发现根据规则除了第一个字节,其他字节都是前两位为10.那么就只剩下6位了。所以移位计算的数字是以6的倍数来进行的。0x80-->10000000、0x3f-->00111111。代码 0x80 | (c & 0x3f) 刚好满足了第二个字节的条件
-
3字节的代码和2字节的代码比较类似
理解了stringToByteBuffer这个方法之后,我们再来看看java中的实现:
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException(); return StringCoding.encode(charsetName, value, 0, value.length); }
没什么好说的,调用了一个StringCoding的一个方法。继续跟踪代码:
static byte[] encode(String charsetName, char[] ca, int off, int len) throws UnsupportedEncodingException { StringEncoder se = deref(encoder); String csn = (charsetName == null) ? "ISO-8859-1" : charsetName; if ((se == null) || !(csn.equals(se.requestedCharsetName()) || csn.equals(se.charsetName()))) { se = null; try { Charset cs = lookupCharset(csn); if (cs != null) se = new StringEncoder(cs, csn); } catch (IllegalCharsetNameException x) {} if (se == null) throw new UnsupportedEncodingException (csn); set(encoder, se); } return se.encode(ca, off, len); }
这段代码的大概的意思猜测是,先根据传递的字符集名称去查找字符集,然后根据字符集创建一个StringEncoder类型的对象。然后调用对象的encode方法。继续跟踪代码:
byte[] encode(char[] ca, int off, int len) { int en = scale(len, ce.maxBytesPerChar()); byte[] ba = new byte[en]; if (len == 0) return ba; if (ce instanceof ArrayEncoder) { int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); return safeTrim(ba, blen, cs, isTrusted); } else { ce.reset(); ByteBuffer bb = ByteBuffer.wrap(ba); CharBuffer cb = CharBuffer.wrap(ca, off, len); try { CoderResult cr = ce.encode(cb, bb, true); if (!cr.isUnderflow()) cr.throwException(); cr = ce.flush(bb); if (!cr.isUnderflow()) cr.throwException(); } catch (CharacterCodingException x) { // Substitution is always enabled, // so this shouldn't happen throw new Error(x); } return safeTrim(ba, bb.position(), cs, isTrusted); } }
这段代码判断StringEncoder的类型。我写个测试用例byte[] x="a".getbytes("utf-8"); 跟踪代码到这里发现走的是 ArrayEncoder这里逻辑。继续跟踪发现ArrayEncoder有多个实现。其中有一个UTF_8类。这个类在nio包中。这里的代码只能通过反编译来看,没有找到源码包:
/* */ public int encode(char[] paramArrayOfChar, int paramInt1, int paramInt2, byte[] paramArrayOfByte) /* */ { /* 627 */ int i = paramInt1 + paramInt2; /* 628 */ int j = 0; /* 629 */ int k = j + Math.min(paramInt2, paramArrayOfByte.length); /* 632 */ while ((j < k) && (paramArrayOfChar[paramInt1] < '')) { /* 633 */ paramArrayOfByte[(j++)] = ((byte)paramArrayOfChar[(paramInt1++)]); /* */ } /* 635 */ while (paramInt1 < i) /* */ { /* 636 */ char c = paramArrayOfChar[(paramInt1++)]; /* 637 */ if (c < '-') /* */ { /* 639 */ paramArrayOfByte[(j++)] = ((byte)c); /* */ } /* 640 */ else if (c < 'ࠀ') /* */ { /* 642 */ paramArrayOfByte[(j++)] = ((byte)(0xC0 | c >> '\006')); /* 643 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | c & 0x3F)); /* */ } /* 644 */ else if (Character.isSurrogate(c)) /* */ { /* 645 */ if (this.sgp == null) { /* 646 */ this.sgp = new Surrogate.Parser(); /* */ } /* 647 */ int m = this.sgp.parse(c, paramArrayOfChar, paramInt1 - 1, i); /* 648 */ if (m < 0) /* */ { /* 649 */ if (malformedInputAction() != CodingErrorAction.REPLACE) { /* 650 */ return -1; /* */ } /* 651 */ paramArrayOfByte[(j++)] = replacement()[0]; /* */ } /* */ else /* */ { /* 653 */ paramArrayOfByte[(j++)] = ((byte)(0xF0 | m >> 18)); /* 654 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | m >> 12 & 0x3F)); /* 655 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | m >> 6 & 0x3F)); /* 656 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | m & 0x3F)); /* 657 */ paramInt1++; /* */ } /* */ } /* */ else /* */ { /* 661 */ paramArrayOfByte[(j++)] = ((byte)(0xE0 | c >> '\f')); /* 662 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | c >> '\006' & 0x3F)); /* 663 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | c & 0x3F)); /* */ } /* */ } /* 666 */ return j; /* */ }
和zookeeper中的差不多,都是在用位运算来实现utf-8的规则。
对比代码的理解如下:
-
zookeeper中实现了3字节的转换,而java的类实现了4字节的转换。
-
代码复杂度上java的比zookeeper要高
直观上我没有发现具体的实现上zookeeper会比较高。
到这里utf-8的实现就完毕了,但这里引起了我的思考:
-
zookeeper为什么需要自己去实现序列化、实现utf-8的转换
-
如果自己去开发一个分布式的系统是否也需要实现这些呢
也许等我在不断的学习zookeeper的源码中会有新的体会和领悟!树立目标,坚持去做,不断的提升自己的理解和领悟,才能超越过去的自己!
相关推荐
apache-zookeeper分布式框架,压缩包内容:(apache-zookeeper-3.7.1-bin.tar.gz、apache-zookeeper-3.7.1.tar.gz、apache-zookeeper-3.6.4-bin.tar.gz、apache-zookeeper-3.6.4.tar.gz、apache-zookeeper-3.5.10-...
apache-zookeeper-3.5.10-bin 环境搭配 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,...
《Zookeeper-3.4.5-cdh5.16.2:分布式协调服务的核心解析》 Apache ZooKeeper,一个高度可靠的分布式协调系统,是大数据生态中的重要组件。本资源包"zookeeper-3.4.5-cdh5.16.2.tar.gz"包含了Zookeeper的3.4.5版本...
apache-zookeeper-3.7.1 apache-zookeeper-3.7.1 apache-zookeeper-3.7.1 apache-zookeeper-3.7.1 apache-zookeeper-3.7.1 apache-zookeeper-3.7.1 apache-zookeeper-3.7.1 apache-zookeeper-3.7.1 apache-zookeeper...
赠送jar包:zookeeper-3.4.10.jar; 赠送原API文档:zookeeper-3.4.10-javadoc.jar; 赠送源代码:zookeeper-3.4.10-sources.jar; 赠送Maven依赖信息文件:zookeeper-3.4.10.pom; 包含翻译后的API文档:zookeeper-...
Zookeeper-3.8.0 是该系统的最新版本,提供了更稳定和高效的服务。 Zookeeper 的核心概念包括节点(Znode)、会话(Session)和观察者(Watcher)。Znode 是 Zookeeper 数据存储的基本单位,类似于文件系统中的节点...
这个压缩包"apache-zookeeper-3.5.7-bin.tar.gz"是Zookeeper的可执行二进制文件包,用于在Linux或Unix类操作系统上部署和运行Zookeeper服务器。 **Zookeeper的基本概念:** 1. **节点(ZNode)**:Zookeeper的数据...
首先,你需要从Apache官方网站或者镜像站点下载ZooKeeper 3.4.10的tar.gz安装包,文件名为"zookeeper-3.4.10.tar.gz"。在Linux环境下,你可以使用`wget`或`curl`命令下载,然后使用`tar`命令解压: ```bash wget ...
apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-...
在 `apache-zookeeper-3.5.6-bin.tar` 这个压缩包中,包含了 Apache ZooKeeper 3.5.6 版本的二进制文件,这是部署和运行 ZooKeeper 服务所必需的。这个版本引入了多项改进和修复,使得 ZooKeeper 更加稳定和高效。 ...
1. **下载与解压**:首先,你需要从官方或镜像站点下载Zookeeper的tar.gz压缩包,即"zookeeper-3.4.5-cdh5.15.1.tar.gz"。下载完成后,使用`tar -zxvf zookeeper-3.4.5-cdh5.15.1.tar.gz`命令进行解压。 2. **配置...
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调...ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在zookeeper-3.4.3\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。
apache-zookeeper-3.6.3-bin.tar的压缩包,解压到本地即可使用,还有zk.sh的脚本以及zoo.cfg和xsync。ZooKeeper 是一个分布式协调服务 ,由 Apache 进行维护。ZooKeeper 可以视为一个高可用的文件系统。ZooKeeper ...
1. 解压`apache-zookeeper-3.8.4-bin.tar`到指定目录。 2. 配置`conf/zoo.cfg`,设置服务器ID、数据存储路径、集群配置等。 3. 启动Zookeeper服务,使用`bin/zkServer.sh start`命令。 4. 使用`bin/zkCli.sh`命令行...
apache-zookeeper-3.7.1-bin.tar.gz 内容概要:通过带着读者手写简化版Spring框架,了解Spring核心原理。在手写Spring源码的过程中会摘取整体框架中的核心逻辑,简化代码实现过程,保留核心功能,例如:IOC, AOP、 Bean...
在压缩包子文件的文件名称列表"zookeeper -3.4.6"中,我们可以推测这可能是一个完整的Zookeeper 3.4.6版本的下载包,除了"zookeeper-3.4.6.jar"外,还可能包括配置文件、文档、示例代码以及其他必要的组件。...
打开“系统属性” -> “高级” -> “环境变量”,在“系统变量”部分新建一个变量,变量名为"ZOOKEEPER_HOME",变量值设置为Zookeeper解压后的路径,即"C:\Zookeeper\apache-zookeeper-3.6.3-bin"。 然后,在系统...
赠送jar包:zookeeper-3.3.3.jar; 赠送原API文档:zookeeper-3.3.3-javadoc.jar; 赠送源代码:zookeeper-3.3.3-sources.jar; 包含翻译后的API文档:zookeeper-3.3.3-javadoc-API文档-中文(简体)版.zip 对应...
总结来说,Zookeeper-3.4.8是一个强大的分布式协调服务,其安装包中的`zookeeper-3.4.8.jar`和`slf4j-api-1.6.1.jar`是运行和管理Zookeeper所必需的。通过理解和掌握Zookeeper的工作原理及其配置,开发者可以有效地...
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性...window下先解压为apache-zookeeper-3.6.1-bin.tar.gz