﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-少年阿宾</title><link>http://www.blogjava.net/stevenjohn/</link><description>那些青春的岁月</description><language>zh-cn</language><lastBuildDate>Fri, 24 Apr 2026 19:58:27 GMT</lastBuildDate><pubDate>Fri, 24 Apr 2026 19:58:27 GMT</pubDate><ttl>60</ttl><item><title>如何用消息系统避免分布式事务？</title><link>http://www.blogjava.net/stevenjohn/archive/2018/01/04/433004.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Wed, 03 Jan 2018 16:01:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2018/01/04/433004.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/433004.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2018/01/04/433004.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/433004.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/433004.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 前阵子从支付宝转账1万块钱到余额宝，这是日常生活的一件普通小事，但作为互联网研发人员的职业病，我就思考支付宝扣除1万之后，如果系统挂掉怎么办，这时余额宝账户并没有增加1万，数据就会出现不一致状况了。上述场景在各个类型的系统中都能找到相似影子，比如在电商系统中，当有用户下单后，除了在订单表插入一条记录外，对应商品表的这个商品数量必须减1吧，怎么保证？！在搜索广告系统中，当用户点击某广告后，除了在点击...&nbsp;&nbsp;<a href='http://www.blogjava.net/stevenjohn/archive/2018/01/04/433004.html'>阅读全文</a><img src ="http://www.blogjava.net/stevenjohn/aggbug/433004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2018-01-04 00:01 <a href="http://www.blogjava.net/stevenjohn/archive/2018/01/04/433004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>微服务优点缺点</title><link>http://www.blogjava.net/stevenjohn/archive/2017/12/31/432996.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Sun, 31 Dec 2017 08:41:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2017/12/31/432996.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/432996.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2017/12/31/432996.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/432996.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/432996.html</trackback:ping><description><![CDATA[<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">微服务架构采用Scale Cube方法设计应用架构，将应用服务按功能拆分成一组相互协作的服务。每个服务负责一组特定、相关的功能。每个服务可以有自己独立的数据库，从而保证与其他服务解耦。</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-weight: bold;">微服务优点</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;">1、<span style="font-family: SimHei, STHeiti; color: #666666; background-color: #ffffff;">通过分解巨大单体式应用为多个服务方法解决了复杂性问题，</span><span style="font-size: 16px; color: #454545; background-color: #ffffff;">每个微服务相对较小</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;">2、每个单体应用不局限于固定的技术栈，<span style="font-family: SimHei, STHeiti; color: #666666; background-color: #ffffff;">开发者可以自由选择开发技术，提供API服务。</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;">3、<span style="font-family: SimHei, STHeiti; color: #666666; background-color: #ffffff;">每个微服务独立的开发，部署</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;">4、单一职责功能，<span style="font-family: Arial; background-color: #ffffff;">每个服务都很简单，只关注于一个业务功能</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;">5、<span style="font-size: 16px; color: #454545; background-color: #ffffff;">易于规模化开发，多个开发团队可以并行开发，每个团队负责一项服务</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">6、改善故障隔离。一个服务宕机不会影响其他的服务</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-weight: bold;">微服务缺点：</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">1.开发者需要应对创建分布式系统所产生的额外的复杂因素</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">l&nbsp; 目前的IDE主要面对的是单体工程程序，无法显示支持分布式应用的开发</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">l&nbsp; 测试工作更加困难</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">l&nbsp; 需要采用服务间的通讯机制</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">l&nbsp; 很难在不采用分布式事务的情况下跨服务实现功能</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">l&nbsp; 跨服务实现要求功能要求团队之间的紧密协作</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">2.部署复杂</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #454545; background-color: #ffffff;">3.内存占用量更高</span></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div><img src ="http://www.blogjava.net/stevenjohn/aggbug/432996.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2017-12-31 16:41 <a href="http://www.blogjava.net/stevenjohn/archive/2017/12/31/432996.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK 源码中 HashMap 的 hash 方法原理是什么？</title><link>http://www.blogjava.net/stevenjohn/archive/2017/12/24/432975.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Sun, 24 Dec 2017 14:38:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2017/12/24/432975.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/432975.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2017/12/24/432975.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/432975.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/432975.html</trackback:ping><description><![CDATA[<div>JDK 的 HashMap 中使用了一个 hash 方法来做 bit shifting，在注释中说明是为了防止一些实现比较差的hashCode() 方法，请问原理是什么？JDK 的源码参见：GrepCode: java.util.HashMap (.java)</div><div>/**</div><div>&nbsp;* Applies a supplemental hash function to a given hashCode, which</div><div>&nbsp;* defends against poor quality hash functions.&nbsp; This is critical</div><div>&nbsp;* because HashMap uses power-of-two length hash tables, that</div><div>&nbsp;* otherwise encounter collisions for hashCodes that do not differ</div><div>&nbsp;* in lower bits. Note: Null keys always map to hash 0, thus index 0.</div><div>&nbsp;*/</div><div>static int hash(int h) {</div><div>&nbsp; &nbsp; // This function ensures that hashCodes that differ only by</div><div>&nbsp; &nbsp; // constant multiples at each bit position have a bounded</div><div>&nbsp; &nbsp; // number of collisions (approximately 8 at default load factor).</div><div></div><div>&nbsp; &nbsp; h ^= (h &gt;&gt;&gt; 20) ^ (h &gt;&gt;&gt; 12);</div><div>&nbsp; &nbsp; return h ^ (h &gt;&gt;&gt; 7) ^ (h &gt;&gt;&gt; 4);</div><div>}</div><div></div><div>PS：网上看见有人说作者本人说原理需要参见圣经《计算机程序设计艺术》的 Vol.3 里头的介绍，不过木有看过神书，求达人介绍</div><div><br /><br /><br /><br /><div> <br />这段代码叫&#8220;扰动函数&#8221;。<br />题主贴的是Java&nbsp;7的HashMap的源码，Java&nbsp;8中这步已经简化了，只做一次16位右位移异或混合，而不是四次，但原理是不变的。下面以Java&nbsp;8的源码为例解释，<br /><br />//Java&nbsp;8中的散列值优化函数staticfinalinthash(Objectkey){inth;return(key==null)?0:(h=key.hashCode())^(h&gt;&gt;&gt;16);//key.hashCode()为哈希算法，返回初始哈希值}<br />大家都知道上面代码里的key.hashCode()函数调用的是key键值类型自带的哈希函数，返回int型散列值。理论上散列值是一个int型，如果直接拿散列值作为下标访问HashMap主数组的话，考虑到2进制32位带符号的int表值范围从-2147483648到2147483648。前后加起来大概40亿的映射空间。只要哈希函数映射得比较均匀松散，一般应用是很难出现碰撞的。但问题是一个40亿长度的数组，内存是放不下的。你想，HashMap扩容之前的数组初始大小才16。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算，得到的余数才能用来访问数组下标。源码中模运算是在这个indexFor(&nbsp;)函数里完成的。<br /><br />bucketIndex&nbsp;=&nbsp;indexFor(hash,&nbsp;table.length);indexFor的代码也很简单，就是把散列值和数组长度做一个"与"操作，<br /><br />static&nbsp;int&nbsp;indexFor(int&nbsp;h,&nbsp;int&nbsp;length)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;h&nbsp;&amp;&nbsp;(length-1);}顺便说一下，这也正好解释了为什么HashMap的数组长度要取2的整次幂。因为这样（数组长度-1）正好相当于一个&#8220;低位掩码&#8221;。&#8220;与&#8221;操作的结果就是散列值的高位全部归零，只保留低位值，用来做数组下标访问。以初始长度16为例，16-1=15。2进制表示是00000000&nbsp;00000000&nbsp;00001111。和某散列值做&#8220;与&#8221;操作如下，结果就是截取了最低的四位值。<br />10100101&nbsp;11000100&nbsp;00100101&amp;	00000000&nbsp;00000000&nbsp;00001111----------------------------------	00000000&nbsp;00000000&nbsp;00000101&nbsp;&nbsp;&nbsp;&nbsp;//高位全部归零，只保留末四位<br />但这时候问题就来了，这样就算我的散列值分布再松散，要是只取最后几位的话，碰撞也会很严重。更要命的是如果散列本身做得不好，分布上成等差数列的漏洞，恰好使最后几个低位呈现规律性重复，就无比蛋疼。这时候&#8220;扰动函数&#8221;的价值就体现出来了，说到这里大家应该猜出来了。看下面这个图，<br /><div style="position: absolute; width: 104px; height: 104px;"></div><img src="http://www.blogjava.net/images/blogjava_net/stevenjohn/4acf898694b8fb53498542dc0c5f765a_hd.jpg" border="0" alt="" /><br /><br />右位移16位，正好是32bit的一半，自己的高半区和低半区做异或，就是为了混合原始哈希码的高位和低位，以此来加大低位的随机性。而且混合后的低位掺杂了高位的部分特征，这样高位的信息也被变相保留下来。最后我们来看一下PeterLawley的一篇专栏文章《An&nbsp;introduction&nbsp;to&nbsp;optimising&nbsp;a&nbsp;hashing&nbsp;strategy》里的的一个实验：他随机选取了352个字符串，在他们散列值完全没有冲突的前提下，对它们做低位掩码，取数组下标。<br /><br /><img src="http://www.blogjava.net/images/blogjava_net/stevenjohn/22222.jpg" border="0" alt="" /><br />结果显示，当HashMap数组长度为512的时候，也就是用掩码取低9位的时候，在没有扰动函数的情况下，发生了103次碰撞，接近30%。而在使用了扰动函数之后只有92次碰撞。碰撞减少了将近10%。看来扰动函数确实还是有功效的。但明显Java&nbsp;8觉得扰动做一次就够了，做4次的话，多了可能边际效用也不大，所谓为了效率考虑就改成一次了。<br />------------------------------------------------------</div><br /><br /><br /><br /><br /><br /><br /><br /><div>https://www.zhihu.com/question/20733617</div><br /><br /><br /></div><img src ="http://www.blogjava.net/stevenjohn/aggbug/432975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2017-12-24 22:38 <a href="http://www.blogjava.net/stevenjohn/archive/2017/12/24/432975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GoLang之方法与接口</title><link>http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Thu, 03 Aug 2017 03:34:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/432720.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/432720.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/432720.html</trackback:ping><description><![CDATA[<p>Go语言没有沿袭传统面向对象编程中的诸多概念，比如继承、虚函数、构造函数和析构函数、隐藏的this指针等。</p> <p>&nbsp;</p> <h2>方法</h2> <p><span style="line-height: 1.5;">Go 语言中同时有函数和方法。<span style="color: #ff0000;">方法就是一个包含了接受者（receiver）的函数</span>，receiver可以是内置类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。<br /></span></p> <p>如下面的这个例子，定义了一个新类型Integer，它和int一样，只是为它内置的int类型增加了个新方法Less()</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Integer <span style="color: #0000ff;">int</span>   func (a Integer) Less(b Integer) bool {     return a &lt; b  }  func main() {     var a Integer = 1       <span style="color: #0000ff;">if</span> a.Less(2) {         fmt.Println("less then 2")     }    }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>可以看出，Go语言在自定义类型的对象中没有C++/Java那种隐藏的this指针，而是在定义成员方法时显式声明了其所属的对象。</p> <p>&nbsp;</p> <p>method的语法如下：</p> <div> <pre>func (r ReceiverType) funcName(parameters) (results)</pre> </div> <p>当调用method时，会将receiver作为函数的第一个参数：</p> <div> <pre>funcName(r, parameters);</pre> </div> <p>所以，receiver是值类型还是指针类型要看method的作用。如果要修改对象的值，就需要传递对象的指针。</p> <p>指针作为Receiver会对实例对象的内容发生操作,而普通类型作为Receiver仅仅是以副本作为操作对象,并不对原实例对象发生操作。</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>func (a *Ingeger) Add(b Integer) {     *a += b }  func main() {     var a Integer = 1      a.Add(3)     fmt.Println("a =", a)     //  a = 4 }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>如果Add方法不使用指针，则a返回的结果不变，这是因为Go语言函数的参数也是基于值传递。</p> <p>注意：<span style="color: #ff0000;">当方法的接受者是指针时，即使用值类型调用那么方法内部也是对指针的操作。</span></p> <p>&nbsp;</p> <p>之前说过，Go语言没有构造函数的概念，通常使用一个全局函数来完成。例如：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>func NewRect(x, y, width, height float64) *Rect {     return &amp;Rect{x, y, width, height} }     func main() {     rect1 := NewRect(1,2,10,20)     fmt.Println(rect1.width) }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>&nbsp;</p> <hr /> <h3><span style="font-size: 14px; line-height: 1.5;">匿名组合</span></h3> <p><span style="line-height: 1.5;">Go语言提供了继承，但是采用了组合的语法，我们将其称为匿名组合，例如：</span></p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Base struct {     name string }  func (base *Base) Set(myname string) {     base.name = myname }  func (base *Base) Get() string {     return base.name }  type Derived struct {     Base     age <span style="color: #0000ff;">int</span>  }  func (derived *Derived) Get() (nm string, ag <span style="color: #0000ff;">int</span>) {     return derived.name, derived.age }   func main() {     b := &amp;Derived{}      b.Set("sina")     fmt.Println(b.Get()) }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>例子中，在Base类型定义了get()和set()两个方法，而Derived类型继承了Base类，并改写了Get()方法，在Derived对象调用Set()方法，会加载基类对应的方法；而调用Get()方法时，加载派生类改写的方法。</p> <p>&nbsp;</p> <p>组合的类型和被组合的类型包含同名成员时，&nbsp;会不会有问题呢？可以参考下面的例子：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Base struct {     name string     age <span style="color: #0000ff;">int</span> }  func (base *Base) Set(myname string, myage <span style="color: #0000ff;">int</span>) {     base.name = myname     base.age = myage }  type Derived struct {     Base     name string }  func main() {     b := &amp;Derived{}      b.Set("sina", 30)     fmt.Println("b.name =",b.name, "\tb.Base.name =", b.Base.name)     fmt.Println("b.age =",b.age, "\tb.Base.age =", b.Base.age) }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>&nbsp;</p> <p>&nbsp;</p> <hr /> <h2>值语义和引用语义</h2> <p>值语义和引用语义的差别在于赋值，比如</p> <div> <pre>b = a b.Modify()</pre> </div> <p><span style="line-height: 1.5;">如果b的修改不会影响a的值，那么此类型属于值类型；如果会影响a的值，那么此类型是引用类型。</span></p> <p>Go语言中的大多数类型都基于值语义，包括：</p> <ul> <li>基本类型，如byte、int、bool、float32、string等；</li> <li><span style="line-height: 1.5;">复合类型，如arry、struct、pointer等；</span></li> </ul> <p>&nbsp;</p> <p>C语言中的数组比较特别，通过函数传递一个数组的时候基于引用语义，但是在结构体定义数组变量的时候基于值语义。而在Go语言中，数组和基本类型没有区别，是很纯粹的值类型，例如：</p> <div> <pre>var a = [3] <span style="color: #0000ff;">int</span>{1,2,3} var b = a b[1]++ fmt.Println(a, b)   // [1 2 3] [1 3 3]</pre> </div> <p>从结果看，b=a赋值语句是数组内容的完整复制，要想表达引用，需要用指针：</p> <div> <pre>var a = [3] <span style="color: #0000ff;">int</span>{1,2,3} var b = &amp;a　　　　// 引用语义 b[1]++ fmt.Println(a, b)   // [1 3 3] [1 3 3]</pre> </div> <p>&nbsp;</p> <p>&nbsp;</p> <hr /> <h2>接口</h2> <p>Interface 是一组抽象方法（未具体实现的方法/仅包含方法名参数返回值的方法）的集合，如果实现了 interface 中的所有方法，即该类/对象就实现了该接口。</p> <p>Interface 的声明格式：</p> <div> <pre>type interfaceName interface {       //方法列表   }  </pre> </div> <p>Interface 可以被任意对象实现，一个类型/对象也可以实现多个 interface；<br /><span style="background-color: #ffff00;">interface的变量可以持有任意实现该interface类型的对象。</span></p> <p>&nbsp;如下面的例子：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>package main      import <span style="color: #800000;">"</span><span style="color: #800000;">fmt</span><span style="color: #800000;">"</span>      type Human <span style="color: #0000ff;">struct</span> {         name <span style="color: #0000ff;">string</span>         age <span style="color: #0000ff;">int</span>         phone <span style="color: #0000ff;">string</span>     }      type Student <span style="color: #0000ff;">struct</span> {         Human <span style="color: #008000;">//</span><span style="color: #008000;">匿名字段</span>         school <span style="color: #0000ff;">string</span>         loan float32     }      type Employee <span style="color: #0000ff;">struct</span> {         Human <span style="color: #008000;">//</span><span style="color: #008000;">匿名字段</span>         company <span style="color: #0000ff;">string</span>         money float32     }      <span style="color: #008000;">//</span><span style="color: #008000;">Human实现SayHi方法</span>     func (h Human) SayHi() {         fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">Hi, I am %s you can call me on %s\n</span><span style="color: #800000;">"</span>, h.name, h.phone)     }      <span style="color: #008000;">//</span><span style="color: #008000;">Human实现Sing方法</span>     func (h Human) Sing(lyrics <span style="color: #0000ff;">string</span>) {         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">La la la la...</span><span style="color: #800000;">"</span>, lyrics)     }      <span style="color: #008000;">//</span><span style="color: #008000;">Employee重载Human的SayHi方法</span>     func (e Employee) SayHi() {         fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">Hi, I am %s, I work at %s. Call me on %s\n</span><span style="color: #800000;">"</span>, e.name,             e.company, e.phone)         }      <span style="color: #008000;">//</span><span style="color: #008000;"> Interface Men被Human,Student和Employee实现     </span><span style="color: #008000;">//</span><span style="color: #008000;"> 因为这三个类型都实现了这两个方法</span>     type Men <span style="color: #0000ff;">interface</span> {         SayHi()         Sing(lyrics <span style="color: #0000ff;">string</span>)     }      func main() {         mike := Student{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Mike</span><span style="color: #800000;">"</span>, <span style="color: #800080;">25</span>, <span style="color: #800000;">"</span><span style="color: #800000;">222-222-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">MIT</span><span style="color: #800000;">"</span>, <span style="color: #800080;">0.00</span>}         paul := Student{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Paul</span><span style="color: #800000;">"</span>, <span style="color: #800080;">26</span>, <span style="color: #800000;">"</span><span style="color: #800000;">111-222-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">Harvard</span><span style="color: #800000;">"</span>, <span style="color: #800080;">100</span>}         sam := Employee{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Sam</span><span style="color: #800000;">"</span>, <span style="color: #800080;">36</span>, <span style="color: #800000;">"</span><span style="color: #800000;">444-222-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">Golang Inc.</span><span style="color: #800000;">"</span>, <span style="color: #800080;">1000</span>}         tom := Employee{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Tom</span><span style="color: #800000;">"</span>, <span style="color: #800080;">37</span>, <span style="color: #800000;">"</span><span style="color: #800000;">222-444-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">Things Ltd.</span><span style="color: #800000;">"</span>, <span style="color: #800080;">5000</span>}          <span style="color: #008000;">//</span><span style="color: #008000;">定义Men类型的变量i</span>         <span style="color: #0000ff;">var</span> i Men          <span style="color: #008000;">//</span><span style="color: #008000;">i能存储Student</span>         i = mike　　　　         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">This is Mike, a Student:</span><span style="color: #800000;">"</span>)         i.SayHi()         i.Sing(<span style="color: #800000;">"</span><span style="color: #800000;">November rain</span><span style="color: #800000;">"</span>)          <span style="color: #008000;">//</span><span style="color: #008000;">i也能存储Employee</span>         i = tom         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">This is tom, an Employee:</span><span style="color: #800000;">"</span>)         i.SayHi()         i.Sing(<span style="color: #800000;">"</span><span style="color: #800000;">Born to be wild</span><span style="color: #800000;">"</span>)          <span style="color: #008000;">//</span><span style="color: #008000;">定义了slice Men</span>         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">Let's use a slice of Men and see what happens</span><span style="color: #800000;">"</span>)         x := make([]Men, <span style="color: #800080;">3</span>)         <span style="color: #008000;">//</span><span style="color: #008000;">这三个都是不同类型的元素，但是他们实现了interface同一个接口</span>         x[<span style="color: #800080;">0</span>], x[<span style="color: #800080;">1</span>], x[<span style="color: #800080;">2</span>] = paul, sam, mike          <span style="color: #0000ff;">for</span> _, value := range x{             value.SayHi()         }     }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <h3>空接口</h3> <p>空interface(interface{})不包含任何的method，正因为如此，<span style="background-color: #ffff00;">所有的类型都实现了空interface</span>。空interface对于描述起不到任何的作用(因为它不包含任何的method），但是<span style="background-color: #ffff00;">空interface在我们需要存储任意类型的数值的时候相当有用，因为它可以存储任意类型的数值。它有点类似于C语言的void*类型。</span></p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre><span style="color: #008000;">//</span><span style="color: #008000;"> 定义a为空接口</span>     <span style="color: #0000ff;">var</span> a <span style="color: #0000ff;">interface</span>{}     <span style="color: #0000ff;">var</span> i <span style="color: #0000ff;">int</span> = <span style="color: #800080;">5</span>     s := <span style="color: #800000;">"</span><span style="color: #800000;">Hello world</span><span style="color: #800000;">"</span>     <span style="color: #008000;">//</span><span style="color: #008000;"> a可以存储任意类型的数值</span>     a = i     a = s</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>interface的变量里面可以存储任意类型的数值（该类型实现了interface），那么我们怎么反向知道这个interface变量里面实际保存了的是哪个类型的对象呢？目前常用的有两种方法：switch测试、Comma-ok断言。</p> <p>&nbsp;</p> <p>switch测试如下：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Element <span style="color: #0000ff;">interface</span>{} type List [] Element  type Person <span style="color: #0000ff;">struct</span> {     name <span style="color: #0000ff;">string</span>     age <span style="color: #0000ff;">int</span>  }  <span style="color: #008000;">//</span><span style="color: #008000;">打印</span> func (p Person) String() <span style="color: #0000ff;">string</span> {     <span style="color: #0000ff;">return</span> <span style="color: #800000;">"</span><span style="color: #800000;">(name: </span><span style="color: #800000;">"</span> + p.name + <span style="color: #800000;">"</span><span style="color: #800000;"> - age: </span><span style="color: #800000;">"</span>+strconv.Itoa(p.age)+ <span style="color: #800000;">"</span><span style="color: #800000;"> years)</span><span style="color: #800000;">"</span> }  func main() {     list := make(List, <span style="color: #800080;">3</span>)     list[<span style="color: #800080;">0</span>] = <span style="color: #800080;">1</span> <span style="color: #008000;">//</span><span style="color: #008000;">an int </span>     list[<span style="color: #800080;">1</span>] = <span style="color: #800000;">"</span><span style="color: #800000;">Hello</span><span style="color: #800000;">"</span> <span style="color: #008000;">//</span><span style="color: #008000;">a string</span>     list[<span style="color: #800080;">2</span>] = Person{<span style="color: #800000;">"</span><span style="color: #800000;">Dennis</span><span style="color: #800000;">"</span>, <span style="color: #800080;">70</span>}       <span style="color: #0000ff;">for</span> index, element := range list{         <span style="color: #0000ff;">switch</span> value := element.(type) {             <span style="color: #0000ff;">case</span> <span style="color: #0000ff;">int</span>:                 fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is an int and its value is %d\n</span><span style="color: #800000;">"</span>, index, value)             <span style="color: #0000ff;">case</span> <span style="color: #0000ff;">string</span>:                 fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a string and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)             <span style="color: #0000ff;">case</span> Person:                 fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a Person and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)             <span style="color: #0000ff;">default</span>:                 fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is of a different type</span><span style="color: #800000;">"</span>, index)         }        }    }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>如果使用Comma-ok断言的话：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>func main() {     list := make(List, <span style="color: #800080;">3</span>)     list[<span style="color: #800080;">0</span>] = <span style="color: #800080;">1</span> <span style="color: #008000;">//</span><span style="color: #008000;"> an int</span>     list[<span style="color: #800080;">1</span>] = <span style="color: #800000;">"</span><span style="color: #800000;">Hello</span><span style="color: #800000;">"</span> <span style="color: #008000;">//</span><span style="color: #008000;"> a string</span>     list[<span style="color: #800080;">2</span>] = Person{<span style="color: #800000;">"</span><span style="color: #800000;">Dennis</span><span style="color: #800000;">"</span>, <span style="color: #800080;">70</span>}      <span style="color: #0000ff;">for</span> index, element := range list {         <span style="color: #0000ff;">if</span> value, ok := element.(<span style="color: #0000ff;">int</span>); ok {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is an int and its value is %d\n</span><span style="color: #800000;">"</span>, index, value)         } <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> value, ok := element.(<span style="color: #0000ff;">string</span>); ok {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a string and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)         } <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> value, ok := element.(Person); ok {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a Person and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)         } <span style="color: #0000ff;">else</span> {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is of a different type\n</span><span style="color: #800000;">"</span>, index)         }     } }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>&nbsp;</p> <h3>嵌入接口</h3> <p>正如struct类型可以包含一个匿名字段，interface也可以嵌套另外一个接口。</p> <p>如果一个interface1作为interface2的一个嵌入字段，那么interface2隐式的包含了interface1里面的method。</p> <p>&nbsp;</p> <p>&nbsp;</p> <h3>反射</h3> <p>所谓反射（reflect）就是能检查程序在运行时的状态。</p> <p>使用reflect一般分成三步，下面简要的讲解一下：要去反射是一个类型的值(这些值都实现了空interface)，首先需要把它转化成reflect对象(reflect.Type或者reflect.Value，根据不同的情况调用不同的函数)。这两种获取方式如下：</p> <div> <pre> t := reflect.TypeOf(i)    <span style="color: #008000;">//</span><span style="color: #008000;">得到类型的元数据,通过t我们能获取类型定义里面的所有元素</span>  v := reflect.ValueOf(i)   <span style="color: #008000;">//</span><span style="color: #008000;">得到实际的值，通过v我们获取存储在里面的值，还可以去改变值</span></pre> </div> <p>&nbsp;</p> <p>转化为reflect对象之后我们就可以进行一些操作了，也就是将reflect对象转化成相应的值，例如</p> <div> <pre>tag := t.Elem().Field(<span style="color: #800080;">0</span>).Tag  <span style="color: #008000;">//</span><span style="color: #008000;">获取定义在struct里面的标签</span> name := v.Elem().Field(<span style="color: #800080;">0</span>).String()  <span style="color: #008000;">//</span><span style="color: #008000;">获取存储在第一个字段里面的值</span></pre> </div> <p>&nbsp;</p> <p>获取反射值能返回相应的类型和数值</p> <div> <pre><span style="color: #0000ff;">var</span> x float64 = <span style="color: #800080;">3.4</span> v := reflect.ValueOf(x) fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">type:</span><span style="color: #800000;">"</span>, v.Type()) fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">kind is float64:</span><span style="color: #800000;">"</span>, v.Kind() == reflect.Float64) fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">value:</span><span style="color: #800000;">"</span>, v.Float())</pre> </div> <p>&nbsp;</p> <p>最后，反射的话，那么反射的字段必须是可修改的，我们前面学习过传值和传引用，这个里面也是一样的道理。反射的字段必须是可读写的意思是，如果下面这样写，那么会发生错误</p> <div> <pre><span style="color: #0000ff;">var</span> x float64 = <span style="color: #800080;">3.4</span> v := reflect.ValueOf(x) v.SetFloat(<span style="color: #800080;">7.1</span>)</pre> </div> <p>&nbsp;</p> <p>如果要修改相应的值，必须这样写</p> <div> <pre><span style="color: #0000ff;">var</span> x float64 = <span style="color: #800080;">3.4</span> p := reflect.ValueOf(&amp;x) v := p.Elem() v.SetFloat(<span style="color: #800080;">7.1</span>)</pre> </div> <p>上面只是对反射的简单介绍，更深入的理解还需要自己在编程中不断的实践。</p> <p>&nbsp;</p> <p>&nbsp;</p> <p><strong>参考文档：</strong></p> <p><a href="http://se77en.cc/2014/05/05/methods-interfaces-and-embedded-types-in-golang/" target="_blank">http://se77en.cc/2014/05/05/methods-interfaces-and-embedded-types-in-golang/</a></p> <p><a href="http://se77en.cc/2014/05/04/choose-whether-to-use-a-value-or-pointer-receiver-on-methods/" target="_blank">http://se77en.cc/2014/05/04/choose-whether-to-use-a-value-or-pointer-receiver-on-methods/<br /></a></p> <p>&nbsp;http://www.cnblogs.com/chenny7/p/4497969.html<br /><br /><br /><br /></p><p><br /><br /></p><img src ="http://www.blogjava.net/stevenjohn/aggbug/432720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2017-08-03 11:34 <a href="http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>老虞要学GoLang-函数(上)</title><link>http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Wed, 02 Aug 2017 08:39:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/432718.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/432718.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/432718.html</trackback:ping><description><![CDATA[<p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">不可或缺的函数，在Go中定义函数的方式如下：</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func (p myType ) funcName ( a, b int , c string ) ( r , s int ) {     return } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">通过函数定义，我们可以看到Go中函数和其他语言中的共性和特性</p><h3><a name="-1" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-1" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>共性</h3><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;">关键字&#8212;&#8212;func</li><li style="margin: 0px; padding: 0px; list-style: disc;">方法名&#8212;&#8212;funcName</li><li style="margin: 0px; padding: 0px; list-style: disc;">入参&#8212;&#8212;&#8212; a,b int,b string</li><li style="margin: 0px; padding: 0px; list-style: disc;">返回值&#8212;&#8212; r,s int</li><li style="margin: 0px; padding: 0px; list-style: disc;">函数体&#8212;&#8212; {}</li></ul><h3><a name="-2" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-2" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>特性</h3><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">Go中函数的特性是非常酷的，给我们带来不一样的编程体验。</p><h4><a name="-3" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-3" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>为特定类型定义函数，即为类型对象定义方法</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">在Go中通过给函数标明所属类型，来给该类型定义方法，上面的&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">p myType</code>&nbsp;即表示给myType声明了一个方法，&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">p myType</code>&nbsp;不是必须的。如果没有，则纯粹是一个函数，通过包名称访问。packageName.funcationName</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如：</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">//定义新的类型double，主要目的是给float64类型扩充方法 type double float64  //判断a是否等于b func (a double) IsEqual(b double) bool {     var r = a - b     if r == 0.0 {         return true     } else if r &lt; 0.0 {         return r &gt; -0.0001     }     return r &lt; 0.0001 }  //判断a是否等于b func IsEqual(a, b float64) bool {     var r = a - b     if r == 0.0 {         return true     } else if r &lt; 0.0 {         return r &gt; -0.0001     }     return r &lt; 0.0001 }  func main() {     var a double = 1.999999     var b double = 1.9999998     fmt.Println(a.IsEqual(b))     fmt.Println(a.IsEqual(3))     fmt.Println( IsEqual( (float64)(a), (float64)(b) ) )  } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">上述示例为 float64 基本类型扩充了方法IsEqual，该方法主要是解决精度问题。 其方法调用方式为：&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">a.IsEqual(double)</code>&nbsp;，如果不扩充方法，我们只能使用函数<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">IsEqual(a, b float64)</code></p><h4><a name="-4" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-4" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>入参中，如果连续的参数类型一致，则可以省略连续多个参数的类型，只保留最后一个类型声明。</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">func IsEqual(a, b float64) bool</code>&nbsp;这个方法就只保留了一个类型声明,此时入参a和b均是float64数据类型。 这样也是可以的：&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">func IsEqual(a, b float64, accuracy int) bool</code></p><h4><a name="-5" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-5" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>变参：入参支持变参,即可接受不确定数量的同一类型的参数</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">func Sum(args ...int)</code>&nbsp;参数args是的slice，其元素类型为int 。经常使用的fmt.Printf就是一个接受任意个数参数的函数&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">fmt.Printf(format string, args ...interface{})</code></p><h4><a name="-6" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-6" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>支持多返回值</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">前面我们定义函数时返回值有两个r,s 。这是非常有用的，我在写C#代码时，常常为了从已有函数中获得更多的信息，需要修改函数签名，使用out ,ref 等方式去获得更多返回结果。而现在使用Go时则很简单，直接在返回值后面添加返回参数即可。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如,在C#中一个字符串转换为int类型时逻辑代码</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">int v=0;  if ( int.TryPase("123456",out v) ) {     //code } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">而在Go中，则可以这样实现,逻辑精简而明确</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">if v,isOk :=int.TryPase("123456") ; isOk {     //code } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">同时在Go中很多函数充分利用了多返回值</p><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;">func (file *File) Write(b []byte) (n int, err error)</li><li style="margin: 0px; padding: 0px; list-style: disc;">func Sincos(x float64) (sin, cos float64)</li></ul><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">那么如果我只需要某一个返回值，而不关心其他返回值的话，我该如何办呢？ 这时可以简单的使用符号下划线&#8221;_&#8220; 来忽略不关心的返回值。如：</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">_, cos = math.Sincos(3.1415) //只需要cos计算的值 </code></pre><h4><a name="-7" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-7" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>命名返回值</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">前面我们说了函数可以有多个返回值，这里我还要说的是，在函数定义时可以给所有的返回值分别命名，这样就能在函数中任意位置给不同返回值复制，而不需要在return语句中才指定返回值。同时也能增强可读性，也提高godoc所生成文档的可读性</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如果不支持命名返回值，我可能会是这样做的</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func ReadFull(r Reader, buf []byte) (int, error) {     var n int     var err error      for len(buf) &gt; 0  {         var nr int         nr, err = r.Read(buf)          n += nr         if err !=nil {             return n,err         }         buf = buf[nr:]     }     return n,err } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">但支持给返回值命名后，实际上就是省略了变量的声明，return时无需写成<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">return n,err</code>&nbsp;而是将直接将值返回</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func ReadFull(r Reader, buf []byte) (n int, err error) {     for len(buf) &gt; 0 &amp;&amp; err == nil {         var nr int         nr, err = r.Read(buf)         n += nr         buf = buf[nr:]     }     return } </code></pre><h4><a name="-8" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-8" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>函数也是&#8220;值&#8221;</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">和Go中其他东西一样，函数也是值，这样就可以声明一个函数类型的变量，将函数作为参数传递。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">声明函数为值的变量(匿名函数:可赋值个变量，也可直接执行)</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">//赋值 fc := func(msg string) {     fmt.Println("you say :", msg) } fmt.Printf("%T \n", fc) fc("hello,my love") //直接执行 func(msg string) {     fmt.Println("say :", msg) }("I love to code") </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">输出结果如下，这里表明fc 的类型为：func(string)</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func(string)  you say : hello,my love say : I love to code </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">将函数作为入参（回调函数），能带来便利。如日志处理，为了统一处理，将信息均通过指定函数去记录日志，且是否记录日志还有开关</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func Log(title string, getMsg func() string) {     //如果开启日志记录,则记录日志     if true {         fmt.Println(title, ":", getMsg())     } } //---------调用-------------- count := 0 msg := func() string {     count++     return "您没有即使提醒我,已触犯法律" } Log("error", msg) Log("warring", msg) Log("info", msg) fmt.Println(count) </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里输出结果如下，count 也发生了变化</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">error : 您没有即使提醒我,已触犯法律 warring : 您没有即使提醒我,已触犯法律 info : 您没有即使提醒我,已触犯法律 3 </code></pre><h4><a name="-9" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-9" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>函数也是&#8220;类型&#8221;</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">你有没有注意到上面示例中的&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">fc := func(msg string)...</code>&nbsp;，既然匿名函数可以赋值给一个变量，同时我们经常这样给int赋值&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">value := 2</code>&nbsp;,是否我们可以声明func(string) 类型 呢，当然是可以的。</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">//一个记录日志的类型：func(string) type saveLog func(msg string)  //将字符串转换为int64,如果转换失败调用saveLog func stringToInt(s string, log saveLog) int64 {      if value, err := strconv.ParseInt(s, 0, 0); err != nil {         log(err.Error())         return 0     } else {         return value     } }  //记录日志消息的具体实现 func myLog(msg string) {     fmt.Println("Find Error:", msg) }  func main() {     stringToInt("123", myLog) //转换时将调用mylog记录日志     stringToInt("s", myLog) } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里我们定义了一个类型，专门用作记录日志的标准接口。在stringToInt函数中如果转换失败则调用我自己定义的接口函数进行日志处理，至于最终执行的哪个函数，则无需关心。</p><h4><a name="defer-" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#defer-" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>defer 延迟函数</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">defer 又是一个创新，它的作用是：延迟执行，在声明时不会立即执行，而是在函数return后时按照后进先出的原则依次执行每一个defer。这样带来的好处是，能确保我们定义的函数能百分之百能够被执行到，这样就能做很多我们想做的事，如释放资源，清理数据，记录日志等</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里我们重点来说明下defer的执行顺序</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func deferFunc() int {     index := 0      fc := func() {          fmt.Println(index, "匿名函数1")         index++          defer func() {             fmt.Println(index, "匿名函数1-1")             index++         }()     }      defer func() {         fmt.Println(index, "匿名函数2")         index++     }()      defer fc()      return func() int {         fmt.Println(index, "匿名函数3")         index++         return index     }() }  func main() {     deferFunc() } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里输出结果如下，</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">0 匿名函数3 1 匿名函数1 2 匿名函数1-1 3 匿名函数2 </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">有如下结论：</p><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;">defer 是在执行完return 后执行</li><li style="margin: 0px; padding: 0px; list-style: disc;">defer 后进先执行</li></ul><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">另外，我们常使用defer去关闭IO,在正常打开文件后，就立刻声明一个defer，这样就不会忘记关闭文件，也能保证在出现异常等不可预料的情况下也能关闭文件。而不像其他语言：<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">try-catch</code>&nbsp;或者&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">using()</code>&nbsp;方式进行处理。</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">file , err :=os.Open(file) if err != nil {     return err } defer file.Close()  //dosomething with file </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">后续，我将讨论： 作用域、传值和传指针 以及 保留函数init(),main()</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">本笔记中所写代码存储位置：</p><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;"><a href="https://github.com/devYu/GoLangStudy/tree/master/codeDemo/defer.go" style="margin: 0px; padding: 1px 3px; color: green; text-decoration: none;">defer.go</a></li><li style="margin: 0px; padding: 0px; list-style: disc;"><a href="https://github.com/devYu/GoLangStudy/tree/master/codeDemo/defineFunctionType.go" style="margin: 0px; padding: 1px 3px; color: green; text-decoration: none;">defineFunctionType.go</a></li><li style="margin: 0px; padding: 0px; list-style: disc;"><a href="https://github.com/devYu/GoLangStudy/tree/master/codeDemo/function.go" style="margin: 0px; padding: 1px 3px; color: green; text-decoration: none;">function.go<br /><br /><br /><br /><div>http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html</div><br /></a></li></ul><img src ="http://www.blogjava.net/stevenjohn/aggbug/432718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2017-08-02 16:39 <a href="http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL触发器Trigger实例篇 </title><link>http://www.blogjava.net/stevenjohn/archive/2016/08/18/431625.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Thu, 18 Aug 2016 09:25:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2016/08/18/431625.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/431625.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2016/08/18/431625.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/431625.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/431625.html</trackback:ping><description><![CDATA[<div><div style="margin:0px; padding:0px; border:0px; background-color:transparent; font-family:微软雅黑,Verdana,Tahoma,'Lucida Grande',Arial,sans-serif; line-height:21px"> <div style="margin:0px; padding:0px; border:0px; font-size:14px; background-color:transparent; font-weight:bold"> MySQL触发器Trigger实例篇</div> <div style="margin:0px; padding:0px; border:0px; background-color:transparent; color:#737373"> <span style="margin:0px; padding:0px; border:0px; background-color:transparent">发表于668 天前</span>&nbsp;<span style="margin:0px; padding:0px; border:0px; background-color:transparent">&#8260;&nbsp;<a target="_blank" href="http://www.sky54.net/?category_name=it" title="查看 IT技术 的全部文章" rel="category" style="text-decoration:none; color:#737373">IT技术</a></span>&nbsp;<span style="margin:0px; padding:0px; border:0px; background-color:transparent">&#8260;&nbsp;<a target="_blank" href="http://www.sky54.net/?p=3043#respond" title="MySQL触发器Trigger实例篇 上的评论" style="text-decoration:none; color:#737373">暂无评论</a></span></div> </div>  <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 以前关注的数据存储过程不太懂其中奥妙，最近遇到跨<a href="http://lib.csdn.net/base/14" title="MySQL知识库" target="_blank" style="color:#df3434; font-weight:bold;">数据库</a>，同时对多个表进行CURD（Create增、Update改、Read读、Delete删），怎么才能让繁琐的数据CURD同步变得更容易呢？相信很多人会首先想到了<a href="http://lib.csdn.net/base/14" title="MySQL知识库" target="_blank" style="color:#df3434; font-weight:bold;">MySQL</a>存储过程、触发器，这种想法确实不错。于是饶有兴趣地亲自写了CUD（增、改、删）触发器的实例，用触发器实现多表数据同步更新。</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <a target="_blank" href="http://www.sky54.net/uploads/2012/03/internet_MYSQL_TRIGGER_.png" style="text-decoration:none; color:#0196e3; outline:none"><img src="http://www.sky54.net/uploads/2012/03/internet_MYSQL_TRIGGER_.png" alt="MySQL触发器Trigger实例篇" title="internet_MYSQL_TRIGGER_" size-full=""  wp-image-3056"="" style="margin:0px auto 10px; padding:0px; border:none; background-color:transparent; display:block" height="415" width="600" /></a></p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <strong>定义： 何为MySQL触发器？</strong></p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 在MySQL Server里面也就是对某一个表的一定的操作，触发某种条件（Insert,Update,Delete 等），从而自动执行的一段程序。从这种意义上讲触发器是一个特殊的存储过程。下面通过MySQL触发器实例，来了解一下触发器的工作过程吧！</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <strong>一、创建MySQL实例数据表：</strong></p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 在mysql的默认的测试test数据库下，创建两个表t_a与t_b：</p></div><div><br /><br />&nbsp;&nbsp;&nbsp; /*Table structure for table `t_a` */<br />&nbsp;&nbsp;&nbsp; DROP TABLE IF EXISTS `t_a`;<br />&nbsp;&nbsp;&nbsp; CREATE TABLE `t_a` (<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `id` smallint(1) unsigned NOT NULL AUTO_INCREMENT,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `username` varchar(20) DEFAULT NULL,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `groupid` mediumint(8) unsigned NOT NULL DEFAULT '0',<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PRIMARY KEY (`id`)<br />&nbsp;&nbsp;&nbsp; ) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=latin1;<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /*Data for the table `t_a` */<br />&nbsp;&nbsp;&nbsp; LOCK TABLES `t_a` WRITE;<br />&nbsp;&nbsp;&nbsp; UNLOCK TABLES;<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /*Table structure for table `t_b` */<br />&nbsp;&nbsp;&nbsp; DROP TABLE IF EXISTS `t_b`;<br />&nbsp;&nbsp;&nbsp; CREATE TABLE `t_b` (<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `id` smallint(1) unsigned NOT NULL AUTO_INCREMENT,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `username` varchar(20) DEFAULT NULL,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `groupid` mediumint(8) unsigned NOT NULL DEFAULT '0',<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PRIMARY KEY (`id`)<br />&nbsp;&nbsp;&nbsp; ) ENGINE=MyISAM AUTO_INCREMENT=57 DEFAULT CHARSET=latin1;<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /*Data for the table `t_b` */<br />&nbsp;&nbsp;&nbsp; LOCK TABLES `t_b` WRITE;<br />&nbsp;&nbsp;&nbsp; UNLOCK TABLES;<br /></div><div><p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 在t_a表上分创建一个CUD（增、改、删）3个触发器，将t_a的表数据与t_b同步实现CUD，注意创建触发器每个表同类事件有且仅有一个对应触发器，为什么只能对一个触发器，不解释啦，看MYSQL的说明帮助文档吧。</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <strong>二、创建MySQL实例触发器：</strong></p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 在实例数据表t_a上依次按照下面步骤创建tr_a_insert、tr_a_update、tr_a_delete三个触发器</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <strong>1、创建INSERT触发器trigger_a_insert：</strong></p></div><div><br /><br />&nbsp;&nbsp;&nbsp; DELIMITER $$<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; USE `test`$$<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; --判断数据库中是否存在tr_a_insert触发器<br />&nbsp;&nbsp;&nbsp; DROP TRIGGER /*!50032 IF EXISTS */ `tr_a_insert`$$<br />&nbsp;&nbsp;&nbsp; --不存在tr_a_insert触发器，开始创建触发器<br />&nbsp;&nbsp;&nbsp; --Trigger触发条件为insert成功后进行触发<br />&nbsp;&nbsp;&nbsp; CREATE<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*!50017 DEFINER = 'root'@'localhost' */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRIGGER `tr_a_insert` AFTER INSERT ON `t_a` <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FOR EACH ROW BEGIN<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --Trigger触发后，同时对t_b新增同步一条数据<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INSERT INTO `t_b` SET username = NEW.username, groupid=NEW.groupid;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END;<br />&nbsp;&nbsp;&nbsp; $$<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; DELIMITER;<br /></div><div><strong>2、创建UPDATE触发器trigger_a_update：</strong></div><div><br /><br />&nbsp;&nbsp;&nbsp; DELIMITER $$<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; USE `test`$$<br />&nbsp;&nbsp;&nbsp; --判断数据库中是否存在tr_a_update触发器<br />&nbsp;&nbsp;&nbsp; DROP TRIGGER /*!50032 IF EXISTS */ `tr_a_update`$$<br />&nbsp;&nbsp;&nbsp; --不存在tr_a_update触发器，开始创建触发器<br />&nbsp;&nbsp;&nbsp; --Trigger触发条件为update成功后进行触发<br />&nbsp;&nbsp;&nbsp; CREATE<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*!50017 DEFINER = 'root'@'localhost' */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRIGGER `tr_a_update` AFTER UPDATE ON `t_a` <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FOR EACH ROW BEGIN <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --Trigger触发后，当t_a表groupid,username数据有更改时，对t_b表同步一条更新后的数据<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF new.groupid != old.groupid OR old.username != new.username THEN<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UPDATE `t_b` SET groupid=NEW.groupid,username=NEW.username WHEREusername=OLD.username AND groupid=OLD.groupid;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END IF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END;<br />&nbsp;&nbsp;&nbsp; $$<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; DELIMITER ;<br /></div><div><strong>3、创建DELETE触发器trigger_a_delete：</strong></div><div><br /><br />&nbsp;&nbsp;&nbsp; DELIMITER $$<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; USE `test`$$<br />&nbsp;&nbsp;&nbsp; --判断数据库中是否存在tr_a_delete触发器<br />&nbsp;&nbsp;&nbsp; DROP TRIGGER /*!50032 IF EXISTS */ `tr_a_delete`$$<br />&nbsp;&nbsp;&nbsp; --不存在tr_a_delete触发器，开始创建触发器<br />&nbsp;&nbsp;&nbsp; --Trigger触发条件为delete成功后进行触发<br />&nbsp;&nbsp;&nbsp; CREATE<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*!50017 DEFINER = 'root'@'localhost' */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRIGGER `tr_a_delete` AFTER DELETE ON `t_a` <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FOR EACH ROW BEGIN<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --t_a表数据删除后，t_b表关联条件相同的数据也同步删除<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DELETE FROM `t_b` WHERE username=Old.username AND groupid=OLD.groupid;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END;<br />&nbsp;&nbsp;&nbsp; $$<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; DELIMITER ;<br /></div><div><p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <strong>三、测试MySQL实例触发器：</strong></p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 分别测试实现t_a与t_b实现数据同步CUD(增、改、删)3个Triggers</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <strong>1、测试MySQL的实例tr_a_insert触发器：</strong></p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 在t_a表中新增一条数据，然后分别查询t_a/t_b表的数据是否数据同步，测试触发器成功标志，t_a表无论在何种情况下，新增了一条或多条记录集时，没有t_b表做任何数据insert操作，它同时新增了一样的多条记录集。</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 下面来进行MySQL触发器实例测试：</p></div><div><br /><br />&nbsp;&nbsp;&nbsp; --t_a表新增一条记录集<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INSERT INTO `t_a` (username,groupid) VALUES ('sky54.net',123)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --查询t_a表<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT id,username,groupid FROM `t_a`<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --查询t_b表<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT id,username,groupid FROM `t_b`<br /></div><div><p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> <strong>2、测试MySQL的实例tr_a_update、tr_a_delete触发器：</strong></p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 这两个MySQL触发器测试原理、步骤与tr_a_insert触发器一样的，先修改/删除一条数据，然后分别查看t_a、t_b表的数据变化情况，数据变化同步说明Trigger实例成功，否则需要逐步排查错误原因。</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 世界上任何一种事物都其其优点和缺点，优点与缺点是自身一个相对立的面。当然这里不是强调&#8220;世界非黑即白&#8221;式的&#8220;二元论&#8221;，&#8220;存在即合理&#8221;嘛。当然 MySQL触发器的优点不说了，说一下不足之处，MySQL  Trigger没有很好的调试、管理环境，难于在各种系统环境下测试，测试比MySQL存储过程要难，所以建议在生成环境下，尽量用存储过程来代替 MySQL触发器。</p> <p style="margin-top:0px; margin-bottom:10px; padding-top:0px; padding-bottom:0px; border:0px; background-color:transparent; text-indent:2em"> 本篇结束前再强调一下，支持触发器的MySQL版本需要5.0以上，5.0以前版本的MySQL升级到5.0以后版本方可使用触发器哦！</p></div><br /><br /><br /><br /><br /><br /><br /><div>http://blog.csdn.net/hireboy/article/details/18079183</div><br /><br /><br /><img src ="http://www.blogjava.net/stevenjohn/aggbug/431625.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2016-08-18 17:25 <a href="http://www.blogjava.net/stevenjohn/archive/2016/08/18/431625.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>聊聊高并发系统之限流特技-1</title><link>http://www.blogjava.net/stevenjohn/archive/2016/06/14/430882.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Tue, 14 Jun 2016 05:38:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2016/06/14/430882.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/430882.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2016/06/14/430882.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/430882.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/430882.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在开发高并发系统时有三把利器用来保护系统：缓存、降级和限流。缓存的目的是提升系统访问速度和增大系统能处理的容量，可谓是抗高并发流量的银弹；而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉，待高峰或者问题解决后再打开；而有些场景并不能用缓存和降级来解决，比如稀缺资源（秒杀、抢购）、写服务（如评论、下单）、频繁的复杂查询（评论的最后几页），因此需有一种手段来限制这些场景的并发/请求量，即限...&nbsp;&nbsp;<a href='http://www.blogjava.net/stevenjohn/archive/2016/06/14/430882.html'>阅读全文</a><img src ="http://www.blogjava.net/stevenjohn/aggbug/430882.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2016-06-14 13:38 <a href="http://www.blogjava.net/stevenjohn/archive/2016/06/14/430882.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>shadowsocks 安装</title><link>http://www.blogjava.net/stevenjohn/archive/2016/05/13/430493.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Fri, 13 May 2016 14:56:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2016/05/13/430493.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/430493.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2016/05/13/430493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/430493.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/430493.html</trackback:ping><description><![CDATA[<h2>Install the Command Line Client</h2><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">If you prefer command line client, then you can install it on your Linux with the following command.</p><h3>Debian</h3><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo apt-get install python-pip sudo pip install shadowsocks</pre><h3>Ubuntu</h3><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">Yes, you can use the above commands to install shadowsocks client on ubuntu. But it will install it under&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">~/.local/bin/</span>&nbsp;directory and it causes loads of trouble. So I suggest using<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">&nbsp;su</span>&nbsp;to become root first and then issue the following two commands.</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">apt-get install python-pip pip install shadowsocks</pre><h3>Fedora/Centos</h3><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo yum install python-setuptools   or   sudo dnf install python-setuptools sudo easy_install pip sudo pip install shadowsocks</pre><h3>OpenSUSE</h3><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo zypper install python-pip sudo pip install shadowsocks</pre><h3>Archlinux</h3><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo pacman -S python-pip sudo pip install shadowsocks</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">As you can see the command of installing shadowsocks client is the same to the command of installing shadowsocks server, because the above command will install both the client and the server. You can verify this by looking at the installation script output</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">Downloading/unpacking shadowsocks Downloading shadowsocks-2.8.2.tar.gz Running setup.py (path:/tmp/pip-build-PQIgUg/shadowsocks/setup.py) egg_info for package shadowsocks  Installing collected packages: shadowsocks Running setup.py install for shadowsocks  <span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #008000;">Installing sslocal script to /usr/local/bin</span> <span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #008000;">Installing ssserver script to /usr/local/bin</span> Successfully installed shadowsocks Cleaning up...</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;"><span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;is the client software and&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">ssserver</span>&nbsp;is the server software. On some Linux distros such as ubuntu, the shadowsocks client&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;is installed under&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/usr/local/bin</span>. On Others such as Arch<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;is installed under&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/usr/bin/</span>. Your can use&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">whereis</span>&nbsp;command to find the exact location.</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">user@debian:~$ whereis sslocal sslocal: /usr/local/bin/sslocal</pre><h2>Create a Configuration File</h2><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">we will create a configuration file under /etc/</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo vi /etc/shadowsocks.json</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">Put the following text in the file. Replace server-ip with your actual IP and set a password.</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">{<br /> "server":"<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #ff0000;">server-ip</span>", <br />"server_port":8000, <br />"local_address": "127.0.0.1", <br />"local_port":1080, <br />"password":"<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #ff0000;">your-password</span>", <br />"timeout":600, <br />"method":"aes-256-cfb" <br />}</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">Save and close the file. Next start the client using command line</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sslocal -c /etc/shadowsocks.json</pre><h2>To run in the background</h2><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo sslocal -c /etc/shadowsocks.json -d start</pre><h2>Auto Start the Client on System Boot</h2><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">Edit&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/etc/rc.local</span>&nbsp;file</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo vi /etc/rc.local</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">Put the following line above the&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">exit 0</span>&nbsp;line:</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo sslocal -c /etc/shadowsocks.json -d start</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">Save and close the file. Next time you start your computer, shadowsocks client will automatically start and connect to your shadowsocks server.</p><h2>Check if It Works</h2><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">After you rebooted your computer, enter the following command in terminal:</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo systemctl status rc-local.service</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">If your sslocal command works then you will get this ouput:</p><br /><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">&#9679; rc-local.service - /etc/rc.local <br /><br />Compatibility Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled) <br />Active: active (running) since Fri 2015-11-27 03:19:25 CST; 2min 39s ago <br />Process: 881 ExecStart=/etc/rc.local start (code=exited, status=0/SUCCESS) <br />CGroup: /system.slice/rc-local.service <br />&#9500;&#9472; 887 watch -n 60 su matrix -c ibam <br />&#9492;&#9472;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #ff0000;">1112 /usr/bin/python /usr/local/bin/sslocal -c /etc/shadowsocks....</span></pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">As you can see from the last line, the&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;command created a process whose pid is 1112 on my machine. It means shadowsocks client is running smoothly. And of course you can tell your browser to connect through your shadowsocks client to see if everything goes well.</p><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline;">If for some reason your&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/etc/rc.local</span>&nbsp;script won&#8217;t run, then check the following post to find the solution.</p><h2 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.75rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;"><a href="https://www.linuxbabe.com/linux-server/how-to-enable-etcrc-local-with-systemd" target="_blank" style="font-family: inherit; font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 600; font-stretch: inherit; vertical-align: baseline; text-decoration: none; color: #005a8c;">How to enable /etc/rc.local with Systemd</a>Install the Command Line Client</h2><h1><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">If you prefer command line client, then you can install it on your Linux with the following command.</p></h1><h3 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.5rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">Debian</h3><h1><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo apt-get install python-pip
sudo pip install shadowsocks</pre></h1><h3 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.5rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">Ubuntu</h3><h1><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">Yes, you can use the above commands to install shadowsocks client on ubuntu. But it will install it under&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">~/.local/bin/</span>&nbsp;directory and it causes loads of trouble. So I suggest using<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">&nbsp;su</span>&nbsp;to become root first and then issue the following two commands.</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">apt-get install python-pip
pip install shadowsocks</pre></h1><h3 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.5rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">Fedora/Centos</h3><h1><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo yum install python-setuptools   or   sudo dnf install python-setuptools
sudo easy_install pip
sudo pip install shadowsocks</pre></h1><h3 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.5rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">OpenSUSE</h3><h1><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo zypper install python-pip
sudo pip install shadowsocks</pre></h1><h3 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.5rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">Archlinux</h3><h1><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo pacman -S python-pip
sudo pip install shadowsocks</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">As you can see the command of installing shadowsocks client is the same to the command of installing shadowsocks server, because the above command will install both the client and the server. You can verify this by looking at the installation script output</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">Downloading/unpacking shadowsocks
Downloading shadowsocks-2.8.2.tar.gz
Running setup.py (path:/tmp/pip-build-PQIgUg/shadowsocks/setup.py) egg_info for package shadowsocks

Installing collected packages: shadowsocks
Running setup.py install for shadowsocks

<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #008000;">Installing sslocal script to /usr/local/bin</span>
<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #008000;">Installing ssserver script to /usr/local/bin</span>
Successfully installed shadowsocks
Cleaning up...</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;is the client software and&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">ssserver</span>&nbsp;is the server software. On some Linux distros such as ubuntu, the shadowsocks client&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;is installed under&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/usr/local/bin</span>. On Others such as Arch<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;is installed under&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/usr/bin/</span>. Your can use&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">whereis</span>&nbsp;command to find the exact location.</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">user@debian:~$ whereis sslocal
sslocal: /usr/local/bin/sslocal</pre></h1><h2 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.75rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">Create a Configuration File</h2><h1><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">we will create a configuration file under /etc/</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo vi /etc/shadowsocks.json</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">Put the following text in the file. Replace server-ip with your actual IP and set a password.</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">{
"server":"<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #ff0000;">server-ip</span>",
"server_port":8000,
"local_address": "127.0.0.1",
"local_port":1080,
"password":"<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #ff0000;">your-password</span>",
"timeout":600,
"method":"aes-256-cfb"
}</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">Save and close the file. Next start the client using command line</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sslocal -c /etc/shadowsocks.json</pre></h1><h2 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.75rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">To run in the background</h2><h1><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo sslocal -c /etc/shadowsocks.json -d start</pre></h1><h2 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.75rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">Auto Start the Client on System Boot</h2><h1><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">Edit&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/etc/rc.local</span>&nbsp;file</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo vi /etc/rc.local</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">Put the following line above the&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">exit 0</span>&nbsp;line:</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo sslocal -c /etc/shadowsocks.json -d start</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">Save and close the file. Next time you start your computer, shadowsocks client will automatically start and connect to your shadowsocks server.</p></h1><h2 style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: 400; font-stretch: inherit; font-size: 1.75rem; line-height: 1.3; font-family: Oswald, Helvetica, Arial, sans-serif; vertical-align: baseline; transition: all 0.5s; color: #1f1e1e; background-color: #ffffff;">Check if It Works</h2><h1><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">After you rebooted your computer, enter the following command in terminal:</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">sudo systemctl status rc-local.service</pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">If your sslocal command works then you will get this ouput:</p><pre style="margin-top: 0px; margin-bottom: 1.875rem; padding: 1.25rem; border: 1px solid #ebebeb; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: Consolas, 'Courier New', Courier, monospace; vertical-align: baseline; white-space: pre-wrap; background: #f7f7f7;">&#9679; rc-local.service - /etc/rc.local Compatibility
Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2015-11-27 03:19:25 CST; 2min 39s ago
Process: 881 ExecStart=/etc/rc.local start (code=exited, status=0/SUCCESS)
CGroup: /system.slice/rc-local.service
&#9500;&#9472; 887 watch -n 60 su matrix -c ibam
&#9492;&#9472;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: #ff0000;">1112 /usr/bin/python /usr/local/bin/sslocal -c /etc/shadowsocks....</span></pre><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">As you can see from the last line, the&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">sslocal</span>&nbsp;command created a process whose pid is 1112 on my machine. It means shadowsocks client is running smoothly. And of course you can tell your browser to connect through your shadowsocks client to see if everything goes well.</p><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;">If for some reason your&nbsp;<span style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 900; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline;">/etc/rc.local</span>&nbsp;script won&#8217;t run, then check the following post to find the solution.</p><p style="margin: 0px 0px 1.25rem; padding: 0px; border: 0px; font-weight: normal; font-stretch: inherit; font-size: 17.008px; line-height: 23.8112px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; vertical-align: baseline; background-color: #ffffff;"><a href="https://www.linuxbabe.com/linux-server/how-to-enable-etcrc-local-with-systemd" target="_blank" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 600; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; text-decoration: none; color: #005a8c;">How to enable /etc/rc.local with Systemd</a></p><br style="font-size: 12pt;" /><br style="font-size: 12pt;" /><br style="font-size: 12pt;" /><div style="font-size: 12pt;"></div></h1><img src ="http://www.blogjava.net/stevenjohn/aggbug/430493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2016-05-13 22:56 <a href="http://www.blogjava.net/stevenjohn/archive/2016/05/13/430493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>httpClient Https 单向不验证(httpClient连接池) </title><link>http://www.blogjava.net/stevenjohn/archive/2016/04/27/430267.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Wed, 27 Apr 2016 11:04:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2016/04/27/430267.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/430267.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2016/04/27/430267.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/430267.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/430267.html</trackback:ping><description><![CDATA[<div>废话少说，直接上代码，以前都是调用别人写好的，现在有时间自己弄下，具体功能如下：<br />1、httpClient+http+线程池：<br />2、httpClient+https(单向不验证证书)+线程池：<br /><br />https在%TOMCAT_HOME%/conf/server.xml里面的配置文件<br /><div>&lt;Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"&nbsp;</div><div>&nbsp; &nbsp; &nbsp;maxThreads="150" scheme="https" secure="true"&nbsp;</div><div>&nbsp; &nbsp; &nbsp;clientAuth="false" keystoreFile="D:/tomcat.keystore"&nbsp;</div><div>&nbsp; &nbsp; &nbsp;keystorePass="heikaim" sslProtocol="TLS" &nbsp;executor="tomcatThreadPool"/&gt;&nbsp;</div>其中&nbsp;clientAuth="false"表示不开启证书验证，只是单存的走https<br /><br /><br /><br /><pre style="background-color: #ffffff; font-family: 宋体; font-size: 9pt;"><span style="color:#000080;font-weight:bold;">package </span>com.abin.lee.util;<br /><br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.commons.collections4.MapUtils;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.commons.lang3.StringUtils;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.*;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.HttpRequestRetryHandler;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.config.CookieSpecs;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.config.RequestConfig;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.entity.UrlEncodedFormEntity;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.methods.CloseableHttpResponse;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.methods.HttpGet;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.methods.HttpPost;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.client.protocol.HttpClientContext;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.config.Registry;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.config.RegistryBuilder;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.conn.ConnectTimeoutException;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.conn.socket.ConnectionSocketFactory;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.conn.socket.PlainConnectionSocketFactory;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.conn.ssl.NoopHostnameVerifier;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.conn.ssl.SSLConnectionSocketFactory;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.entity.StringEntity;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.impl.client.CloseableHttpClient;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.impl.client.HttpClients;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.impl.conn.PoolingHttpClientConnectionManager;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.message.BasicHeader;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.message.BasicNameValuePair;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.protocol.HttpContext;<br /><span style="color:#000080;font-weight:bold;">import </span>org.apache.http.util.EntityUtils;<br /><br /><span style="color:#000080;font-weight:bold;">import </span>javax.net.ssl.*;<br /><span style="color:#000080;font-weight:bold;">import </span>java.io.IOException;<br /><span style="color:#000080;font-weight:bold;">import </span>java.io.InterruptedIOException;<br /><span style="color:#000080;font-weight:bold;">import </span>java.net.UnknownHostException;<br /><span style="color:#000080;font-weight:bold;">import </span>java.nio.charset.Charset;<br /><span style="color:#000080;font-weight:bold;">import </span>java.security.cert.CertificateException;<br /><span style="color:#000080;font-weight:bold;">import </span>java.security.cert.X509Certificate;<br /><span style="color:#000080;font-weight:bold;">import </span>java.util.*;<br /><br /><span style="color:#808080;font-style:italic;">/**<br /></span><span style="color:#808080;font-style:italic;"> * Created with IntelliJ IDEA.<br /></span><span style="color:#808080;font-style:italic;"> * User: abin<br /></span><span style="color:#808080;font-style:italic;"> * Date: 16-4-18<br /></span><span style="color:#808080;font-style:italic;"> * Time: 上午10:24<br /></span><span style="color:#808080;font-style:italic;"> * To change this template use File | Settings | File Templates.<br /></span><span style="color:#808080;font-style:italic;"> */<br /></span><span style="color:#000080;font-weight:bold;">public class </span>HttpClientUtil {<br />    <span style="color:#000080;font-weight:bold;">private static </span>CloseableHttpClient <span style="color:#660e7a;font-style:italic;">httpsClient </span>= <span style="color:#000080;font-weight:bold;">null</span>;<br />    <span style="color:#000080;font-weight:bold;">private static </span>CloseableHttpClient <span style="color:#660e7a;font-style:italic;">httpClient </span>= <span style="color:#000080;font-weight:bold;">null</span>;<br /><br />    <span style="color:#000080;font-weight:bold;">static </span>{<br />        <span style="color:#660e7a;font-style:italic;">httpClient </span>= <span style="font-style:italic;">getHttpClient</span>();<br />        <span style="color:#660e7a;font-style:italic;">httpsClient </span>= <span style="font-style:italic;">getHttpsClient</span>();<br />    }<br /><br />    <span style="color:#000080;font-weight:bold;">public static </span>CloseableHttpClient getHttpClient() {<br />        <span style="color:#000080;font-weight:bold;">try </span>{<br />            <span style="color:#660e7a;font-style:italic;">httpClient </span>= HttpClients.<span style="font-style:italic;">custom</span>()<br />                    .setConnectionManager(PoolManager.<span style="font-style:italic;">getHttpPoolInstance</span>())<br />                    .setConnectionManagerShared(<span style="color:#000080;font-weight:bold;">true</span>)<br />                    .setDefaultRequestConfig(<span style="font-style:italic;">requestConfig</span>())<br />                    .setRetryHandler(<span style="font-style:italic;">retryHandler</span>())<br />                    .build();<br />        } <span style="color:#000080;font-weight:bold;">catch </span>(Exception e) {<br />            e.printStackTrace();<br />        }<br />        <span style="color:#000080;font-weight:bold;">return </span><span style="color:#660e7a;font-style:italic;">httpClient</span>;<br />    }<br /><br /><br />    <span style="color:#000080;font-weight:bold;">public static </span>CloseableHttpClient getHttpsClient() {<br />        <span style="color:#000080;font-weight:bold;">try </span>{<br />            <span style="color:#808080;font-style:italic;">//Secure Protocol implementation.<br /></span> SSLContext ctx = SSLContext.<span style="font-style:italic;">getInstance</span>(<span style="color:#008000;font-weight:bold;">"SSL"</span>);<br />            <span style="color:#808080;font-style:italic;">//Implementation of a trust manager for X509 certificates<br /></span> TrustManager x509TrustManager = <span style="color:#000080;font-weight:bold;">new </span>X509TrustManager() {<br />                <span style="color:#000080;font-weight:bold;">public void </span>checkClientTrusted(X509Certificate[] xcs,<br />                                               String string) <span style="color:#000080;font-weight:bold;">throws </span>CertificateException {<br />                }<br />                <span style="color:#000080;font-weight:bold;">public void </span>checkServerTrusted(X509Certificate[] xcs,<br />                                               String string) <span style="color:#000080;font-weight:bold;">throws </span>CertificateException {<br />                }<br />                <span style="color:#000080;font-weight:bold;">public </span>X509Certificate[] getAcceptedIssuers() {<br />                    <span style="color:#000080;font-weight:bold;">return null</span>;<br />                }<br />            };<br />            ctx.init(<span style="color:#000080;font-weight:bold;">null</span>, <span style="color:#000080;font-weight:bold;">new </span>TrustManager[]{x509TrustManager}, <span style="color:#000080;font-weight:bold;">null</span>);<br />            <span style="color:#808080;font-style:italic;">//首先设置全局的标准cookie策略<br /></span><span style="color:#808080;font-style:italic;">//            RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).build();<br /></span> ConnectionSocketFactory connectionSocketFactory = <span style="color:#000080;font-weight:bold;">new </span>SSLConnectionSocketFactory(ctx, <span style="color:#660e7a;font-style:italic;">hostnameVerifier</span>);<br />            Registry&lt;ConnectionSocketFactory&gt; socketFactoryRegistry = RegistryBuilder.&lt;ConnectionSocketFactory&gt;<span style="font-style:italic;">create</span>()<br />                    .register(<span style="color:#008000;font-weight:bold;">"http"</span>, PlainConnectionSocketFactory.<span style="color:#660e7a;font-weight:bold;font-style:italic;">INSTANCE</span>)<br />                    .register(<span style="color:#008000;font-weight:bold;">"https"</span>, connectionSocketFactory).build();<br />            <span style="color:#808080;font-style:italic;">// 设置连接池<br /></span> <span style="color:#660e7a;font-style:italic;">httpsClient </span>= HttpClients.<span style="font-style:italic;">custom</span>()<br />                    .setConnectionManager(PoolsManager.<span style="font-style:italic;">getHttpsPoolInstance</span>(socketFactoryRegistry))<br />                    .setConnectionManagerShared(<span style="color:#000080;font-weight:bold;">true</span>)<br />                    .setDefaultRequestConfig(<span style="font-style:italic;">requestConfig</span>())<br />                    .setRetryHandler(<span style="font-style:italic;">retryHandler</span>())<br />                    .build();<br />        } <span style="color:#000080;font-weight:bold;">catch </span>(Exception e) {<br />            e.printStackTrace();<br />        }<br />        <span style="color:#000080;font-weight:bold;">return </span><span style="color:#660e7a;font-style:italic;">httpsClient</span>;<br />    }<br /><br />    <span style="color:#808080;font-style:italic;">// 配置请求的超时设置<br /></span><span style="color:#808080;font-style:italic;">    //首先设置全局的标准cookie策略<br /></span> <span style="color:#000080;font-weight:bold;">public static </span>RequestConfig requestConfig(){<br />        RequestConfig requestConfig = RequestConfig.<span style="font-style:italic;">custom</span>()<br />                .setCookieSpec(CookieSpecs.<span style="color:#660e7a;font-weight:bold;font-style:italic;">STANDARD_STRICT</span>)<br />                .setConnectionRequestTimeout(<span style="color:#0000ff;">20000</span>)<br />                .setConnectTimeout(<span style="color:#0000ff;">20000</span>)<br />                .setSocketTimeout(<span style="color:#0000ff;">20000</span>)<br />                .build();<br />        <span style="color:#000080;font-weight:bold;">return </span>requestConfig;<br />    }<br /><br />    <span style="color:#000080;font-weight:bold;">public static </span>HttpRequestRetryHandler retryHandler(){<br />        <span style="color:#808080;font-style:italic;">//请求重试处理<br /></span> HttpRequestRetryHandler httpRequestRetryHandler = <span style="color:#000080;font-weight:bold;">new </span>HttpRequestRetryHandler() {<br />            <span style="color:#000080;font-weight:bold;">public boolean </span>retryRequest(IOException exception,<span style="color:#000080;font-weight:bold;">int </span>executionCount, HttpContext context) {<br />                <span style="color:#000080;font-weight:bold;">if </span>(executionCount &gt;= <span style="color:#0000ff;">5</span>) {<span style="color:#808080;font-style:italic;">// 如果已经重试了5次，就放弃<br /></span> <span style="color:#000080;font-weight:bold;">return false</span>;<br />                }<br />                <span style="color:#000080;font-weight:bold;">if </span>(exception <span style="color:#000080;font-weight:bold;">instanceof </span>NoHttpResponseException) {<span style="color:#808080;font-style:italic;">// 如果服务器丢掉了连接，那么就重试<br /></span> <span style="color:#000080;font-weight:bold;">return true</span>;<br />                }<br />                <span style="color:#000080;font-weight:bold;">if </span>(exception <span style="color:#000080;font-weight:bold;">instanceof </span>SSLHandshakeException) {<span style="color:#808080;font-style:italic;">// 不要重试SSL握手异常<br /></span> <span style="color:#000080;font-weight:bold;">return false</span>;<br />                }<br />                <span style="color:#000080;font-weight:bold;">if </span>(exception <span style="color:#000080;font-weight:bold;">instanceof </span>InterruptedIOException) {<span style="color:#808080;font-style:italic;">// 超时<br /></span> <span style="color:#000080;font-weight:bold;">return false</span>;<br />                }<br />                <span style="color:#000080;font-weight:bold;">if </span>(exception <span style="color:#000080;font-weight:bold;">instanceof </span>UnknownHostException) {<span style="color:#808080;font-style:italic;">// 目标服务器不可达<br /></span> <span style="color:#000080;font-weight:bold;">return false</span>;<br />                }<br />                <span style="color:#000080;font-weight:bold;">if </span>(exception <span style="color:#000080;font-weight:bold;">instanceof </span>ConnectTimeoutException) {<span style="color:#808080;font-style:italic;">// 连接被拒绝<br /></span> <span style="color:#000080;font-weight:bold;">return false</span>;<br />                }<br />                <span style="color:#000080;font-weight:bold;">if </span>(exception <span style="color:#000080;font-weight:bold;">instanceof </span>SSLException) {<span style="color:#808080;font-style:italic;">// ssl握手异常<br /></span> <span style="color:#000080;font-weight:bold;">return false</span>;<br />                }<br /><br />                HttpClientContext clientContext = HttpClientContext.<span style="font-style:italic;">adapt</span>(context);<br />                HttpRequest request = clientContext.getRequest();<br />                <span style="color:#808080;font-style:italic;">// 如果请求是幂等的，就再次尝试<br /></span> <span style="color:#000080;font-weight:bold;">if </span>(!(request <span style="color:#000080;font-weight:bold;">instanceof </span>HttpEntityEnclosingRequest)) {<br />                    <span style="color:#000080;font-weight:bold;">return true</span>;<br />                }<br />                <span style="color:#000080;font-weight:bold;">return false</span>;<br />            }<br />        };<br />        <span style="color:#000080;font-weight:bold;">return </span>httpRequestRetryHandler;<br />    }<br /><br /><br /><br />    <span style="color:#808080;font-style:italic;">//创建HostnameVerifier<br /></span><span style="color:#808080;font-style:italic;">    //用于解决javax.net.ssl.SSLException: hostname in certificate didn't match: &lt;123.125.97.66&gt; != &lt;123.125.97.241&gt;<br /></span> <span style="color:#000080;font-weight:bold;">static </span>HostnameVerifier <span style="color:#660e7a;font-style:italic;">hostnameVerifier </span>= <span style="color:#000080;font-weight:bold;">new </span>NoopHostnameVerifier(){<br />        <span style="color:#808000;">@Override<br /></span> <span style="color:#000080;font-weight:bold;">public boolean </span>verify(String s, SSLSession sslSession) {<br />            <span style="color:#000080;font-weight:bold;">return super</span>.verify(s, sslSession);<br />        }<br />    };<br /><br /><br />    <span style="color:#000080;font-weight:bold;">public static class </span>PoolManager {<br />        <span style="color:#000080;font-weight:bold;">public static </span>PoolingHttpClientConnectionManager <span style="color:#660e7a;font-style:italic;">clientConnectionManager </span>= <span style="color:#000080;font-weight:bold;">null</span>;<br />        <span style="color:#000080;font-weight:bold;">private static int </span><span style="color:#660e7a;font-style:italic;">maxTotal </span>= <span style="color:#0000ff;">200</span>;<br />        <span style="color:#000080;font-weight:bold;">private static int </span><span style="color:#660e7a;font-style:italic;">defaultMaxPerRoute </span>= <span style="color:#0000ff;">100</span>;<br /><br />        <span style="color:#000080;font-weight:bold;">private </span>PoolManager(){<br />            <span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>.setMaxTotal(<span style="color:#660e7a;font-style:italic;">maxTotal</span>);<br />            <span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>.setDefaultMaxPerRoute(<span style="color:#660e7a;font-style:italic;">defaultMaxPerRoute</span>);<br />        }<br /><br />        <span style="color:#000080;font-weight:bold;">private static class </span>PoolManagerHolder{<br />            <span style="color:#000080;font-weight:bold;">public static  </span>PoolManager <span style="color:#660e7a;font-style:italic;">instance </span>= <span style="color:#000080;font-weight:bold;">new </span>PoolManager();<br />        }<br /><br />        <span style="color:#000080;font-weight:bold;">public static </span>PoolManager getInstance() {<br />            <span style="color:#000080;font-weight:bold;">if</span>(<span style="color:#000080;font-weight:bold;">null </span>== <span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>)<br />                <span style="color:#660e7a;font-style:italic;">clientConnectionManager </span>= <span style="color:#000080;font-weight:bold;">new </span>PoolingHttpClientConnectionManager();<br />            <span style="color:#000080;font-weight:bold;">return </span>PoolManagerHolder.<span style="color:#660e7a;font-style:italic;">instance</span>;<br />        }<br /><br />        <span style="color:#000080;font-weight:bold;">public static </span>PoolingHttpClientConnectionManager getHttpPoolInstance() {<br />            PoolManager.<span style="font-style:italic;">getInstance</span>();<br /><span style="color:#808080;font-style:italic;">//            System.out.println("getAvailable=" + clientConnectionManager.getTotalStats().getAvailable());<br /></span><span style="color:#808080;font-style:italic;">//            System.out.println("getLeased=" + clientConnectionManager.getTotalStats().getLeased());<br /></span><span style="color:#808080;font-style:italic;">//            System.out.println("getMax=" + clientConnectionManager.getTotalStats().getMax());<br /></span><span style="color:#808080;font-style:italic;">//            System.out.println("getPending="+clientConnectionManager.getTotalStats().getPending());<br /></span> <span style="color:#000080;font-weight:bold;">return </span>PoolManager.<span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>;<br />        }<br /><br /><br />    }<br /><br />    <span style="color:#000080;font-weight:bold;">public static class </span>PoolsManager {<br />        <span style="color:#000080;font-weight:bold;">public static </span>PoolingHttpClientConnectionManager <span style="color:#660e7a;font-style:italic;">clientConnectionManager </span>= <span style="color:#000080;font-weight:bold;">null</span>;<br />        <span style="color:#000080;font-weight:bold;">private static int </span><span style="color:#660e7a;font-style:italic;">maxTotal </span>= <span style="color:#0000ff;">200</span>;<br />        <span style="color:#000080;font-weight:bold;">private static int </span><span style="color:#660e7a;font-style:italic;">defaultMaxPerRoute </span>= <span style="color:#0000ff;">100</span>;<br /><br />        <span style="color:#000080;font-weight:bold;">private </span>PoolsManager(){<br />            <span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>.setMaxTotal(<span style="color:#660e7a;font-style:italic;">maxTotal</span>);<br />            <span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>.setDefaultMaxPerRoute(<span style="color:#660e7a;font-style:italic;">defaultMaxPerRoute</span>);<br />        }<br /><br />        <span style="color:#000080;font-weight:bold;">private static class </span>PoolsManagerHolder{<br />            <span style="color:#000080;font-weight:bold;">public static  </span>PoolsManager <span style="color:#660e7a;font-style:italic;">instance </span>= <span style="color:#000080;font-weight:bold;">new </span>PoolsManager();<br />        }<br /><br />        <span style="color:#000080;font-weight:bold;">public static </span>PoolsManager getInstance(Registry&lt;ConnectionSocketFactory&gt; socketFactoryRegistry) {<br />            <span style="color:#000080;font-weight:bold;">if</span>(<span style="color:#000080;font-weight:bold;">null </span>== <span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>)<br />                <span style="color:#660e7a;font-style:italic;">clientConnectionManager </span>= <span style="color:#000080;font-weight:bold;">new </span>PoolingHttpClientConnectionManager(socketFactoryRegistry);<br />            <span style="color:#000080;font-weight:bold;">return </span>PoolsManagerHolder.<span style="color:#660e7a;font-style:italic;">instance</span>;<br />        }<br /><br />        <span style="color:#000080;font-weight:bold;">public static </span>PoolingHttpClientConnectionManager getHttpsPoolInstance(Registry&lt;ConnectionSocketFactory&gt; socketFactoryRegistry) {<br />            PoolsManager.<span style="font-style:italic;">getInstance</span>(socketFactoryRegistry);<br /><span style="color:#808080;font-style:italic;">//            System.out.println("getAvailable=" + clientConnectionManager.getTotalStats().getAvailable());<br /></span><span style="color:#808080;font-style:italic;">//            System.out.println("getLeased=" + clientConnectionManager.getTotalStats().getLeased());<br /></span><span style="color:#808080;font-style:italic;">//            System.out.println("getMax=" + clientConnectionManager.getTotalStats().getMax());<br /></span><span style="color:#808080;font-style:italic;">//            System.out.println("getPending="+clientConnectionManager.getTotalStats().getPending());<br /></span> <span style="color:#000080;font-weight:bold;">return </span>PoolsManager.<span style="color:#660e7a;font-style:italic;">clientConnectionManager</span>;<br />        }<br /><br />    }<br /><br />    <span style="color:#000080;font-weight:bold;">public static </span>String httpPost(Map&lt;String, String&gt; request, String httpUrl){<br />        String result = <span style="color:#008000;font-weight:bold;">""</span>;<br />        CloseableHttpClient httpClient = <span style="font-style:italic;">getHttpClient</span>();<br />        <span style="color:#000080;font-weight:bold;">try </span>{<br />            <span style="color:#000080;font-weight:bold;">if</span>(MapUtils.<span style="font-style:italic;">isEmpty</span>(request))<br />                <span style="color:#000080;font-weight:bold;">throw new </span>Exception(<span style="color:#008000;font-weight:bold;">"请求参数不能为空"</span>);<br />            HttpPost httpPost = <span style="color:#000080;font-weight:bold;">new </span>HttpPost(httpUrl);<br />            List&lt;NameValuePair&gt; nvps = <span style="color:#000080;font-weight:bold;">new </span>ArrayList&lt;NameValuePair&gt;();<br />            <span style="color:#000080;font-weight:bold;">for</span>(Iterator&lt;Map.Entry&lt;String, String&gt;&gt; iterator=request.entrySet().iterator(); iterator.hasNext();){<br />                Map.Entry&lt;String, String&gt; entry = iterator.next();<br />                nvps.add(<span style="color:#000080;font-weight:bold;">new </span>BasicNameValuePair(entry.getKey(), entry.getValue()));<br />            }<br />            httpPost.setEntity(<span style="color:#000080;font-weight:bold;">new </span>UrlEncodedFormEntity(nvps, Consts.<span style="color:#660e7a;font-weight:bold;font-style:italic;">UTF_8</span>));<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing request: " </span>+ httpPost.getRequestLine());<br />            CloseableHttpResponse response = httpClient.execute(httpPost);<br />            result = EntityUtils.<span style="font-style:italic;">toString</span>(response.getEntity());<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing response: "</span>+ result);<br />        } <span style="color:#000080;font-weight:bold;">catch </span>(Exception e) {<br />            <span style="color:#000080;font-weight:bold;">throw new </span>RuntimeException(e);<br />        } <span style="color:#000080;font-weight:bold;">finally </span>{<br />            <span style="color:#000080;font-weight:bold;">try </span>{<br />                httpClient.close();<br />            } <span style="color:#000080;font-weight:bold;">catch </span>(IOException e) {<br />                e.printStackTrace();<br />            }<br />        }<br />        <span style="color:#000080;font-weight:bold;">return </span>result;<br />    }<br /><br />    <span style="color:#000080;font-weight:bold;">public static </span>String httpPost(String json, String httpUrl, Map&lt;String, String&gt; headers){<br />        String result = <span style="color:#008000;font-weight:bold;">""</span>;<br />        CloseableHttpClient httpClient = <span style="font-style:italic;">getHttpClient</span>();<br />        <span style="color:#000080;font-weight:bold;">try </span>{<br />            <span style="color:#000080;font-weight:bold;">if</span>(StringUtils.<span style="font-style:italic;">isBlank</span>(json))<br />                <span style="color:#000080;font-weight:bold;">throw new </span>Exception(<span style="color:#008000;font-weight:bold;">"请求参数不能为空"</span>);<br />            HttpPost httpPost = <span style="color:#000080;font-weight:bold;">new </span>HttpPost(httpUrl);<br />            <span style="color:#000080;font-weight:bold;">for</span>(Iterator&lt;Map.Entry&lt;String, String&gt;&gt; iterator=headers.entrySet().iterator();iterator.hasNext();){<br />                Map.Entry&lt;String, String&gt; entry = iterator.next();<br />                Header header = <span style="color:#000080;font-weight:bold;">new </span>BasicHeader(entry.getKey(), entry.getValue());<br />                httpPost.setHeader(header);<br />            }<br />            httpPost.setEntity(<span style="color:#000080;font-weight:bold;">new </span>StringEntity(json, Charset.<span style="font-style:italic;">forName</span>(<span style="color:#008000;font-weight:bold;">"UTF-8"</span>)));<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing request: " </span>+ httpPost.getRequestLine());<br />            CloseableHttpResponse response = httpClient.execute(httpPost);<br />            result = EntityUtils.<span style="font-style:italic;">toString</span>(response.getEntity());<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing response: "</span>+ result);<br />        } <span style="color:#000080;font-weight:bold;">catch </span>(Exception e) {<br />            <span style="color:#000080;font-weight:bold;">throw new </span>RuntimeException(e);<br />        } <span style="color:#000080;font-weight:bold;">finally </span>{<br />            <span style="color:#000080;font-weight:bold;">try </span>{<br />                httpClient.close();<br />            } <span style="color:#000080;font-weight:bold;">catch </span>(IOException e) {<br />                e.printStackTrace();<br />            }<br />        }<br />        <span style="color:#000080;font-weight:bold;">return </span>result;<br />    }<br /><br />    <span style="color:#000080;font-weight:bold;">public static </span>String httpGet(String httpUrl, Map&lt;String, String&gt; headers) {<br />        String result = <span style="color:#008000;font-weight:bold;">""</span>;<br />        CloseableHttpClient httpClient = <span style="font-style:italic;">getHttpClient</span>();<br />        <span style="color:#000080;font-weight:bold;">try </span>{<br />            HttpGet httpGet = <span style="color:#000080;font-weight:bold;">new </span>HttpGet(httpUrl);<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing request: " </span>+ httpGet.getRequestLine());<br />            <span style="color:#000080;font-weight:bold;">for</span>(Iterator&lt;Map.Entry&lt;String, String&gt;&gt; iterator=headers.entrySet().iterator();iterator.hasNext();){<br />                Map.Entry&lt;String, String&gt; entry = iterator.next();<br />                Header header = <span style="color:#000080;font-weight:bold;">new </span>BasicHeader(entry.getKey(), entry.getValue());<br />                httpGet.setHeader(header);<br />            }<br />            CloseableHttpResponse response = httpClient.execute(httpGet);<br />            result = EntityUtils.<span style="font-style:italic;">toString</span>(response.getEntity());<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing response: "</span>+ result);<br />        } <span style="color:#000080;font-weight:bold;">catch </span>(Exception e) {<br />            <span style="color:#000080;font-weight:bold;">throw new </span>RuntimeException(e);<br />        } <span style="color:#000080;font-weight:bold;">finally </span>{<br />            <span style="color:#000080;font-weight:bold;">try </span>{<br />                httpClient.close();<br />            } <span style="color:#000080;font-weight:bold;">catch </span>(IOException e) {<br />                e.printStackTrace();<br />            }<br />        }<br />        <span style="color:#000080;font-weight:bold;">return </span>result;<br />    }<br /><br /><br />    <span style="color:#000080;font-weight:bold;">public static </span>String httpGet(String httpUrl) {<br />        String result = <span style="color:#008000;font-weight:bold;">""</span>;<br />        CloseableHttpClient httpClient = <span style="font-style:italic;">getHttpClient</span>();<br />        <span style="color:#000080;font-weight:bold;">try </span>{<br />            HttpGet httpGet = <span style="color:#000080;font-weight:bold;">new </span>HttpGet(httpUrl);<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing request: " </span>+ httpGet.getRequestLine());<br />            CloseableHttpResponse response = httpClient.execute(httpGet);<br />            result = EntityUtils.<span style="font-style:italic;">toString</span>(response.getEntity());<br />            System.<span style="color:#660e7a;font-weight:bold;font-style:italic;">out</span>.println(<span style="color:#008000;font-weight:bold;">"Executing response: "</span>+ result);<br />        } <span style="color:#000080;font-weight:bold;">catch </span>(Exception e) {<br />            <span style="color:#000080;font-weight:bold;">throw new </span>RuntimeException(e);<br />        } <span style="color:#000080;font-weight:bold;">finally </span>{<br />            <span style="color:#000080;font-weight:bold;">try </span>{<br />                httpClient.close();<br />            } <span style="color:#000080;font-weight:bold;">catch </span>(IOException e) {<br />                e.printStackTrace();<br />            }<br />        }<br />        <span style="color:#000080;font-weight:bold;">return </span>result;<br />    }<br /><br /><br />  </pre></div><div><br /><br /><br />maven依赖：<br /><div>&nbsp; &lt;!--httpclient--&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;dependency&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;artifactId&gt;httpclient&lt;/artifactId&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;version&gt;4.5.2&lt;/version&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/dependency&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;dependency&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;artifactId&gt;httpcore&lt;/artifactId&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;version&gt;4.4.4&lt;/version&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/dependency&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;dependency&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;artifactId&gt;httpmime&lt;/artifactId&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;version&gt;4.5.2&lt;/version&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/dependency&gt;<br /><br /><pre style="background-color: #ffffff; font-family: 宋体; font-size: 9pt;"><span style="background-color:#efefef;">&lt;</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">dependency</span><span style="background-color:#efefef;">&gt;</span><br />    <span style="background-color:#efefef;">&lt;</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">groupId</span><span style="background-color:#efefef;">&gt;</span>org.apache.commons<span style="background-color:#efefef;">&lt;/</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">groupId</span><span style="background-color:#efefef;">&gt;</span><br />    <span style="background-color:#efefef;">&lt;</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">artifactId</span><span style="background-color:#efefef;">&gt;</span>commons-collections4<span style="background-color:#efefef;">&lt;/</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">artifactId</span><span style="background-color:#efefef;">&gt;</span><br />    <span style="background-color:#efefef;">&lt;</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">version</span><span style="background-color:#efefef;">&gt;</span>4.1<span style="background-color:#efefef;">&lt;/</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">version</span><span style="background-color:#efefef;">&gt;</span><br /><span style="background-color:#efefef;">&lt;/</span><span style="color:#000080;background-color:#efefef;font-weight:bold;">dependency</span><span style="background-color:#efefef;">&gt;</span><br /></pre></div></div><img src ="http://www.blogjava.net/stevenjohn/aggbug/430267.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2016-04-27 19:04 <a href="http://www.blogjava.net/stevenjohn/archive/2016/04/27/430267.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Redis 代理服务Twemproxy </title><link>http://www.blogjava.net/stevenjohn/archive/2015/11/03/428041.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Tue, 03 Nov 2015 11:30:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2015/11/03/428041.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/428041.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2015/11/03/428041.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/428041.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/428041.html</trackback:ping><description><![CDATA[<div><h2><span style="font-size:14px">1、twemproxy explore</span></h2> <p style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; margin:10px auto"> &nbsp; &nbsp; &nbsp;<span style="background-color:#ffffff">&nbsp;<span style="color:#333333; font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px">当我们有大量 Redis 或 Memcached 的时候，通常只能通过客户端的一些数据分配算法（比如一致性哈希），</span><span style="color:#333333; font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px">来实现集群存储的特性。</span><span style="color:#333333; font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px">虽然</span><span style="color:#333333; font-size:14px; font-family:tahoma,宋体; line-height:22px">Redis  2.6版本已经发布Redis Cluster，但还不是很成熟适用正式生产环境。<span style="color:#333333; font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px">&nbsp;Redis 的 Cluster 方案还没有正式推出之前，我们<span style="color:#333333; font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px">通过  Proxy 的方式来实现集群<span style="color:#333333; font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px">存储</span>。</span></span></span></span></p> <p style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; margin:10px auto"> </p> <p style="color:#333333; font-family:tahoma,宋体; font-size:14px; line-height:22px"> <span style="background-color:#ffffff">&nbsp; &nbsp; &nbsp; &nbsp;Twitter，世界最大的Redis集群之一部署在Twitter用于为用户提供时间轴数据。Twitter Open Source部门提供了Twemproxy。</span></p> <p style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; margin:10px auto"> <span style="background-color:#ffffff">&nbsp; &nbsp; &nbsp;Twemproxy,也叫nutcraker。是一个twtter开源的一个redis和memcache代理服务器。 redis作为一个高效的缓存服务器，非常具有应用价值。但是当使用比较多的时候，就希望可以通过某种方式 统一进</span>行管理。避免每个应用每个客户端管理连接的松散性。同时在一定程度上变得可以控制。</p> <p style="font-size:14px; font-family:tahoma,宋体; line-height:22px; color:#333333"> <span style="background-color:#efefef">&nbsp; &nbsp;</span><span style="background-color:#ffffff"> &nbsp; Twemproxy是一个快速的单线程代理程序，支持Memcached ASCII协议和更新的Redis协议：</span></p> <p style="font-size:14px; font-family:tahoma,宋体; line-height:22px; color:#333333"> <span style="background-color:#ffffff">&nbsp; &nbsp; &nbsp;它全部用C写成，使用Apache 2.0 License授权。项目在Linux上可以工作，而在OSX上无法编译，因为它依赖了epoll API.</span></p> <p style="font-size:14px; font-family:tahoma,宋体; line-height:22px; color:#333333"> <span style="background-color:#ffffff"><span style="font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px; background-color:#f7f7f7">&nbsp; &nbsp; &nbsp; Twemproxy 通过引入一个代理层，可以将其后端的多台 Redis 或 Memcached 实例进行统一管理与分配，使应用程序只需要在  Twemproxy 上进行操作，而不用关心后面具体有多少个真实的 Redis 或 Memcached 存储。</span>&nbsp;</span></p> <p style="font-size:14px; color:#333333"><strong><span style="font-family:tahoma,宋体"><span style="line-height:22px">2、</span></span><span style="font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px">twemproxy特性：</span></strong></p> <ul style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; margin-left:2px"><ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit"> <p style="margin:10px auto">支持失败节点自动删除</p> <ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit">可以设置重新连接该节点的时间</li><li style="list-style:inherit">可以设置连接多少次之后删除该节点</li><li style="list-style:inherit">该方式适合作为cache存储</li></ul> </li><li style="list-style:inherit"> <p style="margin:10px auto">支持设置HashTag</p> <ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit">通过HashTag可以自己设定将两个KEYhash到同一个实例上去。</li></ul> </li><li style="list-style:inherit"> <p style="margin:10px auto">减少与redis的直接连接数</p> <ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit">保持与redis的长连接</li><li style="list-style:inherit">可设置代理与后台每个redis连接的数目</li></ul> </li><li style="list-style:inherit"> <p style="margin:10px auto">自动分片到后端多个redis实例上</p> <ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit">多种hash算法：<span style="font-family:Verdana,Arial,Helvetica,sans-serif; font-size:14px; line-height:25px">能够使用不同的策略和散列函数支持一致性hash。</span></li><li style="list-style:inherit">可以设置后端实例的权重</li></ul> </li><li style="list-style:inherit"> <p style="margin:10px auto">避免单点问题</p> <ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit">可以平行部署多个代理层.client自动选择可用的一个</li></ul> </li><li style="list-style:inherit"> <p style="margin:10px auto">支持redis pipelining request</p> <p style="margin:10px auto"><span style="font-family:Verdana,Arial,Helvetica,sans-serif; font-size:14px; line-height:25px">&nbsp; &nbsp; &nbsp;支持请求的流式与批处理，降低来回的消耗</span><br /> </p> </li><li style="list-style:inherit"> <p style="margin:10px auto">支持状态监控</p> <ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit">可设置状态监控ip和端口，访问ip和端口可以得到一个json格式的状态信息串</li><li style="list-style:inherit">可设置监控信息刷新间隔时间</li></ul> </li><li style="list-style:inherit"> <p style="margin:10px auto">高吞吐量</p> <ul style="list-style-type:disc; margin-left:10px"><li style="list-style:inherit">连接复用，内存复用。</li><li style="list-style:inherit">将多个连接请求，组成reids pipelining统一向redis请求。</li></ul> </li></ul></ul> <p style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; margin:10px auto"> &nbsp; &nbsp; &nbsp;另外可以修改redis的源代码，抽取出redis中的前半部分，作为一个中间代理层。最终都是通过linux下的epoll 事件机制提高并发效率，其中nutcraker本身也是使用epoll的事件机制。并且在性能测试上的表现非常出色。</p> <p style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; margin:10px auto"> </p> <h2><a name="t2"></a><span style="font-size:14px">3、twemproxy问题与不足</span></h2> <span style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; background-color:#ffffff"></span> <div id="cnblogs_post_body" style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; word-break:normal!important"> <span style="background-color:#ffffff"><span style="font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px"><br /> </span></span></div> <span style="font-family:Verdana,Arial,Helvetica,sans-serif; font-size:14px"><span style="line-height:25px">Twemproxy 由于其自身原理限制，有一些不足之处，如：&nbsp;</span></span><br style="font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px" /> <ul style="font-size:14px; font-family:Helvetica,Tahoma,Arial,sans-serif; line-height:25.200000762939453px; margin:0px 0px 1.5em; padding:0px"><li style="margin:0px 0px 0.25em 30px; padding:0px"><span style="background-color:#ffffff">不支持针对多个值的操作，比如取sets的子交并补等（MGET 和 DEL 除外）</span></li><li style="margin:0px 0px 0.25em 30px; padding:0px"><span style="background-color:#ffffff">不支持Redis的事务操作</span></li><li style="margin:0px 0px 0.25em 30px; padding:0px"><span style="background-color:#ffffff">出错提示还不够完善</span></li><li style="margin:0px 0px 0.25em 30px; padding:0px">也不支持select操作</li></ul> <p style="font-size:14px; font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px"> </p>  <div id="blog_post_info_block" style="margin-top:20px"> <div id="blog_post_info"> <div id="BlogPostCategory" style="font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px"> <h2><a name="t3"></a><span style="font-size:14px"><span style="font-family:Helvetica,Tahoma,Arial,sans-serif; line-height:25.200000762939453px; background-color:#f7f7f7">4、安装与配置</span>&nbsp;</span></h2>  <div id="BlogPostCategory"><span style="font-size:14px; font-family:Helvetica,Tahoma,Arial,sans-serif; line-height:25.200000762939453px; background-color:#f7f7f7">具体的安装步骤可用查看github：<a href="https://github.com/twitter/twemproxy" target="_blank">https://github.com/twitter/twemproxy</a></span></div> Twemproxy 的安装，主要命令如下：&nbsp;</div> <div id="BlogPostCategory"><span style="font-family:Helvetica,Tahoma,Arial,sans-serif"></span><div>apt-get install automake &nbsp;<br />apt-get install libtool &nbsp;<br />git clone git://github.com/twitter/twemproxy.git &nbsp;<br />cd twemproxy &nbsp;<br />autoreconf -fvi &nbsp;<br />./configure --enable-debug=log &nbsp;<br />make &nbsp;<br />src/nutcracker -h</div> <div id="BlogPostCategory" style="font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px"> <span style="font-size:14px; font-family:Helvetica,Tahoma,Arial,sans-serif; line-height:25.200000762939453px; background-color:#f7f7f7"><br /> </span></div> <span style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="line-height:25px">通过上面的命令就算安装好了，然后是具体的配置，下面是一个典型的配置&nbsp;</span></span></div> <div id="BlogPostCategory" style="font-family:Verdana,Arial,Helvetica,sans-serif; line-height:25px; font-size:14px"> <div>&nbsp;&nbsp;&nbsp; redis1: &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listen: 127.0.0.1:6379 #使用哪个端口启动Twemproxy &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redis: true #是否是Redis的proxy &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hash: fnv1a_64 #指定具体的hash函数 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; distribution: ketama #具体的hash算法 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; auto_eject_hosts: true #是否在结点无法响应的时候临时摘除结点 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeout: 400 #超时时间（毫秒） &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; server_retry_timeout: 2000 #重试的时间（毫秒） &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; server_failure_limit: 1 #结点故障多少次就算摘除掉 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; servers: #下面表示所有的Redis节点（IP:端口号:权重） &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 127.0.0.1:6380:1 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 127.0.0.1:6381:1 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 127.0.0.1:6382:1 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; redis2: &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listen: 0.0.0.0:10000 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redis: true &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hash: fnv1a_64 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; distribution: ketama &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; auto_eject_hosts: false &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeout: 400 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; servers: &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 127.0.0.1:6379:1 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 127.0.0.1:6380:1 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 127.0.0.1:6381:1 &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 127.0.0.1:6382:1&nbsp;</div><br style="font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px; background-color:#f7f7f7" /> <span style="font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.200000762939453px; background-color:#f7f7f7">你可以同时开启多个 Twemproxy 实例，它们都可以进行读写，这样你的应用程序就可以完全避免所谓的单点故障。 <br /></span></div></div></div></div><br /><br /><div>http://blog.csdn.net/hguisu/article/details/9174459/</div><img src ="http://www.blogjava.net/stevenjohn/aggbug/428041.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2015-11-03 19:30 <a href="http://www.blogjava.net/stevenjohn/archive/2015/11/03/428041.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>