-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.json
1 lines (1 loc) · 305 KB
/
search.json
1
[{"title":"其他JDK命令","url":"https://yangzhiw.github.io/2017/10/12/其他JDK命令/","content":"<h2 id=\"javah命令-C-Header-and-Stub-File-Generator\"><a href=\"#javah命令-C-Header-and-Stub-File-Generator\" class=\"headerlink\" title=\"javah命令(C Header and Stub File Generator)\"></a>javah命令(C Header and Stub File Generator)</h2><p>javah是用于根据JAVA本地方法,生成对应的c语言头文件及相应的stub文件的命令,使用比较简单,使用示例可以查看这篇文章:JNI简单示例,包括C语言实现及调用。</p>\n<h2 id=\"jconsole命令-Java-Monitoring-and-Management-Console\"><a href=\"#jconsole命令-Java-Monitoring-and-Management-Console\" class=\"headerlink\" title=\"jconsole命令(Java Monitoring and Management Console)\"></a>jconsole命令(Java Monitoring and Management Console)</h2><p>jconsole:一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。用java写的GUI程序,用来监控VM,并可监控远程的VM,非常易用,而且功能非常强。命令行里打 jconsole,选则进程就可以了。<br>需要注意的就是在运行jconsole之前,必须要先设置环境变量DISPLAY,否则会报错误,Linux下设置环境变量如下:<br>export DISPLAY=:0.0</p>\n<h2 id=\"jvisualvm命令-Java-Virtual-Machine-Monitoring-Troubleshooting-and-Profiling-Tool\"><a href=\"#jvisualvm命令-Java-Virtual-Machine-Monitoring-Troubleshooting-and-Profiling-Tool\" class=\"headerlink\" title=\"jvisualvm命令(Java Virtual Machine Monitoring, Troubleshooting, and Profiling Tool)\"></a>jvisualvm命令(Java Virtual Machine Monitoring, Troubleshooting, and Profiling Tool)</h2><p>visualvm同jconsole都是一个基于图形化界面的、可以查看本地及远程的JAVA GUI监控工具,Jvisualvm同jconsole的使用方式一样,直接在命令行打入Jvisualvm即可启动,不过Jvisualvm相比,界面更美观一些,数据更实时。</p>\n<h2 id=\"jinfo命令-Java-Configuration-Info\"><a href=\"#jinfo命令-Java-Configuration-Info\" class=\"headerlink\" title=\"jinfo命令(Java Configuration Info)\"></a>jinfo命令(Java Configuration Info)</h2><p>jinfo可以输出并修改运行时的java 进程的opts。用处比较简单,用于输出JAVA系统参数及命令行参数。用法是jinfo -opt pid 如:查看2788的MaxPerm大小可以用 jinfo -flag MaxPermSize 2788。</p>\n"},{"title":"jstat命令","url":"https://yangzhiw.github.io/2017/10/12/jstat命令/","content":"<h1 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h1><p>Jstat用于监控基于HotSpot的JVM,对其堆的使用情况进行实时的命令行的统计,使用jstat我们可以对指定的JVM做如下监控:</p>\n<ul>\n<li>类的加载及卸载情况</li>\n<li>查看新生代、老生代及持久代的容量及使用情况</li>\n<li>查看新生代、老生代及持久代的垃圾收集情况,包括垃圾回收的次数及垃圾回收所占用的时间</li>\n<li>查看新生代中Eden区及Survior区中容量及分配情况等<br>jstat工具特别强大,它有众多的可选项,通过提供多种不同的监控维度,使我们可以从不同的维度来了解到当前JVM堆的使用情况。详细查看堆内各个部分的使用量,使用的时候必须加上待统计的Java进程号,可选的不同维度参数以及可选的统计频率参数。</li>\n</ul>\n<h1 id=\"语法\"><a href=\"#语法\" class=\"headerlink\" title=\"语法\"></a>语法</h1><pre><code>jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]\n\ngeneralOption - 单个的常用的命令行选项,如-help, -options, 或 -version。\n\noutputOptions -一个或多个输出选项,由单个的statOption选项组成,可以和-t, -h, and -J等选项配合使用。\n</code></pre><p>statOption:<br>class 用于查看类加载情况的统计<br>compiler 用于查看HotSpot中即时编译器编译情况的统计<br>gc 用于查看JVM中堆的垃圾收集情况的统计<br>gccapacity 用于查看新生代、老生代及持久代的存储容量情况<br>gccause 用于查看垃圾收集的统计情况(这个和-gcutil选项一样),如果有发生垃圾收集,它还会显示最后一次及当前正在发生垃圾收集的原因。<br>gcnew 用于查看新生代垃圾收集的情况<br>gcnewcapacity 用于查看新生代的存储容量情况<br>gcold 用于查看老生代及持久代发生GC的情况<br>gcoldcapacity 用于查看老生代的容量<br>gcpermcapacity 用于查看持久代的容量<br>gcutil 用于查看新生代、老生代及持代垃圾收集的情况<br>printcompilation HotSpot编译方法的统计</p>\n<pre><code>-h n\n 用于指定每隔几行就输出列头,如果不指定,默认是只在第一行出现列头。\n\n-JjavaOption\n 用于将给定的javaOption传给java应用程序加载器,例如,“-J-Xms48m”将把启动内存设置为48M。如果想查看可以传递哪些选项到应用程序加载器中\n\n-t n\n 用于在输出内容的第一列显示时间戳,这个时间戳代表的时JVM开始启动到现在的时间(注:在IBM JDK5中是没有这个选项的)。\n\nvmid - VM的进程号,即当前运行的java进程号。\n还有两个关于显示频率的选项:\ninterval–间隔时间,单位可以是秒或者毫秒,通过指定s或ms确定,默认单位为毫秒。\ncount-打印次数,如果缺省则打印无数次。\n</code></pre><h1 id=\"不同的统计维度(statOption)及输出说明\"><a href=\"#不同的统计维度(statOption)及输出说明\" class=\"headerlink\" title=\"不同的统计维度(statOption)及输出说明\"></a>不同的统计维度(statOption)及输出说明</h1><h2 id=\"class-类加载情况的统计\"><a href=\"#class-类加载情况的统计\" class=\"headerlink\" title=\"-class 类加载情况的统计\"></a>-class 类加载情况的统计</h2><p>列名 说明<br>Loaded 加载了的类的数量<br>Bytes 加载了的类的大小,单为Kb<br>Unloaded 卸载了的类的数量<br>Bytes 卸载了的类的大小,单为Kb<br>Time 花在类的加载及卸载的时间</p>\n<h2 id=\"compiler-HotSpot中即时编译器编译情况的统计\"><a href=\"#compiler-HotSpot中即时编译器编译情况的统计\" class=\"headerlink\" title=\"-compiler HotSpot中即时编译器编译情况的统计\"></a>-compiler HotSpot中即时编译器编译情况的统计</h2><p>列名 说明<br>Compiled 编译任务执行的次数<br>Failed 编译任务执行失败的次数<br>Invalid 编译任务非法执行的次数<br>Time 执行编译花费的时间<br>FailedType 最后一次编译失败的编译类型<br>FailedMethod 最后一次编译失败的类名及方法名</p>\n<h2 id=\"gc-JVM中堆的垃圾收集情况的统计\"><a href=\"#gc-JVM中堆的垃圾收集情况的统计\" class=\"headerlink\" title=\"-gc JVM中堆的垃圾收集情况的统计\"></a>-gc JVM中堆的垃圾收集情况的统计</h2><p>列名 说明<br>S0C 新生代中Survivor space中S0当前容量的大小(KB)<br>S1C 新生代中Survivor space中S1当前容量的大小(KB)<br>S0U 新生代中Survivor space中S0容量使用的大小(KB)<br>S1U 新生代中Survivor space中S1容量使用的大小(KB)<br>EC Eden space当前容量的大小(KB)<br>EU Eden space容量使用的大小(KB)<br>OC Old space当前容量的大小(KB)<br>OU Old space使用容量的大小(KB)<br>PC Permanent space当前容量的大小(KB)<br>PU Permanent space使用容量的大小(KB)<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>YGCT 从应用程序启动到采样时 Young GC 所用的时间(秒)<br>FGC 从应用程序启动到采样时发生 Full GC 的次数<br>FGCT 从应用程序启动到采样时 Full GC 所用的时间(秒)<br>GCT T从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC</p>\n<h2 id=\"gccapacity-新生代、老生代及持久代的存储容量情况\"><a href=\"#gccapacity-新生代、老生代及持久代的存储容量情况\" class=\"headerlink\" title=\"-gccapacity 新生代、老生代及持久代的存储容量情况\"></a>-gccapacity 新生代、老生代及持久代的存储容量情况</h2><p>列名 说明<br>NGCMN 新生代的最小容量大小(KB)<br>NGCMX 新生代的最大容量大小(KB)<br>NGC 当前新生代的容量大小(KB)<br>S0C 当前新生代中survivor space 0的容量大小(KB)<br>S1C 当前新生代中survivor space 1的容量大小(KB)<br>EC Eden space当前容量的大小(KB)<br>OGCMN 老生代的最小容量大小(KB)<br>OGCMX 老生代的最大容量大小(KB)<br>OGC 当前老生代的容量大小(KB)<br>OC 当前老生代的空间容量大小(KB)<br>PGCMN 持久代的最小容量大小(KB)<br>PGCMX 持久代的最大容量大小(KB)<br>PGC 当前持久代的容量大小(KB)<br>PC 当前持久代的空间容量大小(KB)<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>FGC 从应用程序启动到采样时发生 Full GC 的次数</p>\n<h2 id=\"gccause-用于查看垃圾收集的统计情况,包括最近发生垃圾的原因\"><a href=\"#gccause-用于查看垃圾收集的统计情况,包括最近发生垃圾的原因\" class=\"headerlink\" title=\"-gccause 用于查看垃圾收集的统计情况,包括最近发生垃圾的原因\"></a>-gccause 用于查看垃圾收集的统计情况,包括最近发生垃圾的原因</h2><p>列名 说明<br>LGCC 最后一次垃圾收集的原因,可能为“unknown GCCause”、“System.gc()”等<br>GCC 当前垃圾收集的原因</p>\n<h2 id=\"gcnew-新生代垃圾收集的情况\"><a href=\"#gcnew-新生代垃圾收集的情况\" class=\"headerlink\" title=\"-gcnew 新生代垃圾收集的情况\"></a>-gcnew 新生代垃圾收集的情况</h2><p>列名 说明<br>S0C 当前新生代中survivor space 0的容量大小(KB)<br>S1C 当前新生代中survivor space 1的容量大小(KB)<br>S0U S0已经使用的大小(KB)<br>S1U S1已经使用的大小(KB)<br>TT Tenuring threshold,要了解这个参数,我们需要了解一点Java内存对象的结构,在Sun JVM中,(除了数组之外的)对象都有两个机器字(words)的头部。第一个字中包含这个对象的标示哈希码以及其他一些类似锁状态和等标识信息,第二个字中包含一个指向对象的类的引用,其中第二个字节就会被垃圾收集算法使用到。<br>在新生代中做垃圾收集的时候,每次复制一个对象后,将增加这个对象的收集计数,当一个对象在新生代中被复制了一定次数后,该算法即判定该对象是长周期的对象,把他移动到老生代,这个阈值叫着tenuring threshold。这个阈值用于表示某个/些在执行批定次数youngGC后还活着的对象,即使此时新生的的Survior没有满,也同样被认为是长周期对象,将会被移到老生代中。<br>MTT Maximum tenuring threshold,用于表示TT的最大值。<br>DSS Desired survivor size (KB).可以参与这里:<a href=\"http://blog.csdn.net/yangjun2/article/details/6542357\" target=\"_blank\" rel=\"external\">http://blog.csdn.net/yangjun2/article/details/6542357</a><br>EC Eden space当前容量的大小(KB)<br>EU Eden space已经使用的大小(KB)<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>YGCT 从应用程序启动到采样时 Young GC 所用的时间(单位秒)</p>\n<h2 id=\"gcnewcapacity-新生代的存储容量情况\"><a href=\"#gcnewcapacity-新生代的存储容量情况\" class=\"headerlink\" title=\"gcnewcapacity 新生代的存储容量情况\"></a>gcnewcapacity 新生代的存储容量情况</h2><p>列名 说明<br>NGCMN 新生代的最小容量大小(KB)<br>NGCMX 新生代的最大容量大小(KB)<br>NGC 当前新生代的容量大小(KB)<br>S0CMX 新生代中SO的最大容量大小(KB)<br>S0C 当前新生代中SO的容量大小(KB)<br>S1CMX 新生代中S1的最大容量大小(KB)<br>S1C 当前新生代中S1的容量大小(KB)<br>ECMX 新生代中Eden的最大容量大小(KB)<br>EC 当前新生代中Eden的容量大小(KB)<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>FGC 从应用程序启动到采样时发生 Full GC 的次数</p>\n<h2 id=\"gcold-老生代及持久代发生GC的情况\"><a href=\"#gcold-老生代及持久代发生GC的情况\" class=\"headerlink\" title=\"-gcold 老生代及持久代发生GC的情况\"></a>-gcold 老生代及持久代发生GC的情况</h2><p>列名 说明<br>PC 当前持久代容量的大小(KB)<br>PU 持久代使用容量的大小(KB)<br>OC 当前老年代容量的大小(KB)<br>OU 老年代使用容量的大小(KB)<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>FGC 从应用程序启动到采样时发生 Full GC 的次数<br>FGCT 从应用程序启动到采样时 Full GC 所用的时间(单位秒)<br>GCT 从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC</p>\n<h2 id=\"gcoldcapacity-老生代的存储容量情况\"><a href=\"#gcoldcapacity-老生代的存储容量情况\" class=\"headerlink\" title=\"-gcoldcapacity 老生代的存储容量情况\"></a>-gcoldcapacity 老生代的存储容量情况</h2><p>列名 说明<br>OGCMN 老生代的最小容量大小(KB)<br>OGCMX 老生代的最大容量大小(KB)<br>OGC 当前老生代的容量大小(KB)<br>OC 当前新生代的空间容量大小(KB)<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>FGC 从应用程序启动到采样时发生 Full GC 的次数<br>FGCT 从应用程序启动到采样时 Full GC 所用的时间(单位秒)<br>GCT 从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC</p>\n<h2 id=\"gcpermcapacity-持久代的存储容量情况\"><a href=\"#gcpermcapacity-持久代的存储容量情况\" class=\"headerlink\" title=\"-gcpermcapacity 持久代的存储容量情况\"></a>-gcpermcapacity 持久代的存储容量情况</h2><p>列名 说明<br>PGCMN 持久代的最小容量大小(KB)<br>PGCMX 持久代的最大容量大小(KB)<br>PGC 当前持久代的容量大小(KB)<br>PC 当前持久代的空间容量大小(KB)<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>FGC 从应用程序启动到采样时发生 Full GC 的次数<br>FGCT 从应用程序启动到采样时 Full GC 所用的时间(单位秒)<br>GCT 从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC</p>\n<h2 id=\"gcutil-新生代、老生代及持代垃圾收集的情况\"><a href=\"#gcutil-新生代、老生代及持代垃圾收集的情况\" class=\"headerlink\" title=\"-gcutil 新生代、老生代及持代垃圾收集的情况\"></a>-gcutil 新生代、老生代及持代垃圾收集的情况</h2><p>列名 说明<br>S0 Heap上的 Survivor space 0 区已使用空间的百分比<br>S1 Heap上的 Survivor space 1 区已使用空间的百分比<br>E Heap上的 Eden space 区已使用空间的百分比<br>O Heap上的 Old space 区已使用空间的百分比<br>P Perm space 区已使用空间的百分比<br>YGC 从应用程序启动到采样时发生 Young GC 的次数<br>YGCT 从应用程序启动到采样时 Young GC 所用的时间(单位秒)<br>FGC 从应用程序启动到采样时发生 Full GC 的次数<br>FGCT 从应用程序启动到采样时 Full GC 所用的时间(单位秒)<br>GCT 从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC</p>\n<h2 id=\"printcompilation-HotSpot编译方法的统计\"><a href=\"#printcompilation-HotSpot编译方法的统计\" class=\"headerlink\" title=\"-printcompilation HotSpot编译方法的统计\"></a>-printcompilation HotSpot编译方法的统计</h2><p>HotSpot编译方法的统计<br>列名 说明<br>Compiled 编译任务执行的次数<br>Size 方法的字节码所占的字节数<br>Type 编译类型<br>Method 指定确定被编译方法的类名及方法名,类名中使名“/”而不是“.”做为命名分隔符,方法名是被指定的类中的方法,这两个字段的格式是由HotSpot中的“-XX:+PrintComplation”选项确定的。</p>\n<h1 id=\"使用示例\"><a href=\"#使用示例\" class=\"headerlink\" title=\"使用示例\"></a>使用示例</h1><p>jstat -gcutil 11111</p>\n"},{"title":"jstack命令","url":"https://yangzhiw.github.io/2017/10/12/jstack命令/","content":"<h2 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h2><p>jstack用于打印出给定的java进程ID或corefile或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项”-J-d64”,Windows的jstack使用方式只支持以下的这种方式:<br>jstack [-l] pid<br>如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。</p>\n<h2 id=\"命令格式\"><a href=\"#命令格式\" class=\"headerlink\" title=\"命令格式\"></a>命令格式</h2><p>jstack [ option ] pid<br>jstack [ option ] executable core<br>jstack [ option ] [server-id@]remote-hostname-or-IP</p>\n<h2 id=\"常用参数说明\"><a href=\"#常用参数说明\" class=\"headerlink\" title=\"常用参数说明\"></a>常用参数说明</h2><ul>\n<li><p>options:<br>executable Java executable from which the core dump was produced.<br>(可能是产生core dump的java可执行程序)<br>core 将被打印信息的core dump文件<br>remote-hostname-or-IP 远程debug服务的主机名或ip<br>server-id 唯一id,假如一台主机上多个远程debug服务 </p>\n</li>\n<li><p>基本参数:<br>-F当’jstack [-l] pid’没有响应的时候强制打印栈信息<br>-l长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.<br>-m打印java和native c/c++框架的所有栈信息.<br>-h | -help打印帮助信息<br>pid 需要被打印配置信息的java进程id,可以用jps查询.</p>\n</li>\n</ul>\n"},{"title":"jps命令","url":"https://yangzhiw.github.io/2017/10/12/jps命令/","content":"<h2 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h2><p>用来查看基于HotSpot的JVM里面中,所有具有访问权限的Java进程的具体状态, 包括进程ID,进程启动的路径及启动参数等等,与unix上的ps类似,只不过jps是用来显示java进程,可以把jps理解为ps的一个子集。<br>使用jps时,如果没有指定hostid,它只会显示本地环境中所有的Java进程;如果指定了hostid,它就会显示指定hostid上面的java进程,不过这需要远程服务上开启了jstatd服务,可以参看前面的jstatd章节来启动jstad服务。</p>\n<h2 id=\"命令格式\"><a href=\"#命令格式\" class=\"headerlink\" title=\"命令格式\"></a>命令格式</h2><p>jps [options] [hostid]</p>\n<h2 id=\"常用参数说明\"><a href=\"#常用参数说明\" class=\"headerlink\" title=\"常用参数说明\"></a>常用参数说明</h2><p>-q 忽略输出的类名、Jar名以及传递给main方法的参数,只输出pid。<br>-m 输出传递给main方法的参数,如果是内嵌的JVM则输出为null。<br>-l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径。<br>-v 输出传给JVM的参数。<br>-J 用于传递jvm选项到由javac调用的java加载器中,例如,“-J-Xms48m”将把启动内存设置为48M,使用-J选项可以非常方便的向基于Java的开发的底层虚拟机应用程序传递参数。</p>\n<h2 id=\"服务器标识\"><a href=\"#服务器标识\" class=\"headerlink\" title=\"服务器标识\"></a>服务器标识</h2><p>hostid指定了目标的服务器,它的语法如下:<br>[protocol:][[//]hostname][:port][/servername]<br>protocol - 如果protocol及hostname都没有指定,那表示的是与当前环境相关的本地协议,如果指定了hostname却没有指定protocol,那么protocol的默认就是rmi。<br>hostname - 服务器的IP或者名称,没有指定则表示本机。<br>port - 远程rmi的端口,如果没有指定则默认为1099。<br>Servername - 注册到RMI注册中心中的jstatd的名称。</p>\n<p>如:启动了名为AlternateJstatdServerName的jstatd服务<br>rmiregistry 2020&jstatd -J-Djava.security.policy=all.policy -p 2020 -n AlternateJstatdServerName</p>\n"},{"title":"jmap命令(Java Memory Map)","url":"https://yangzhiw.github.io/2017/10/12/jmap命令-Java-Memory-Map/","content":"<h2 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h2><p>打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。</p>\n<p>可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。使用方法 jmap -histo pid。如果连用SHELL jmap -histo pid>a.log可以将其保存到文本中去,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象。jmap -dump:format=b,file=outfile 3024可以将3024进程的内存heap输出出来到outfile文件里,再配合MAT(内存分析工具(Memory Analysis Tool),使用参见:<a href=\"http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx)或与jhat\" target=\"_blank\" rel=\"external\">http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx)或与jhat</a> (Java Heap Analysis Tool)一起使用,能够以图像的形式直观的展示当前内存是否有问题。<br>64位机上使用需要使用如下方式:<br>jmap -J-d64 -heap pid</p>\n<h2 id=\"命令格式\"><a href=\"#命令格式\" class=\"headerlink\" title=\"命令格式\"></a>命令格式</h2><p>jmap [ option ] pid<br>jmap [ option ] executable core<br>jmap [ option ] [server-id@]remote-hostname-or-IP</p>\n<h2 id=\"参数说明\"><a href=\"#参数说明\" class=\"headerlink\" title=\"参数说明\"></a>参数说明</h2><ul>\n<li><p>options<br>executable Java executable from which the core dump was produced.<br>(可能是产生core dump的java可执行程序)<br>core 将被打印信息的core dump文件<br>remote-hostname-or-IP 远程debug服务的主机名或ip<br>server-id 唯一id,假如一台主机上多个远程debug服务 </p>\n</li>\n<li><p>基本参数<br>-dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.<br>-finalizerinfo 打印正等候回收的对象的信息.<br>-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.<br>-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.<br>-permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来.<br>-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效.<br>-h | -help 打印辅助信息<br>-J 传递参数给jmap启动的jvm.<br>pid 需要被打印配相信息的java进程id,创业与打工的区别 - 博文预览,可以用jps查问.</filename></p>\n</li>\n</ul>\n"},{"title":"Java并发编程实战总结","url":"https://yangzhiw.github.io/2017/09/12/Java并发编程实战总结/","content":"<h1 id=\"线程安全性\"><a href=\"#线程安全性\" class=\"headerlink\" title=\"线程安全性\"></a>线程安全性</h1><ul>\n<li>竞态条件:又有不恰当的执行顺序而出现的的不正确的结果</li>\n<li>当某个线程请求一个由其他线程持有的锁时,发出请求的线程就会阻塞。然而,由于内置锁是可重入的,因此如果某个线程视图获得一个已经由它自己持有的锁,那么这个请求就会成功</li>\n<li>一种常见的加锁约定是,将所有的可变状态都封装在对象内部,并通过对象的内置锁对所有访问可变状态的代码路径进行同步,使得在该对象上不会发生并发访问</li>\n<li>当执行时间较长的计算或者可能无法快速完成的操作时(例如,网络I/O或控制台I/O),一定不要持有锁</li>\n</ul>\n<h1 id=\"对象的共享\"><a href=\"#对象的共享\" class=\"headerlink\" title=\"对象的共享\"></a>对象的共享</h1><ol>\n<li><p>非原子的64位操作:多线程程序中使用共享且可变的long和double等类型的变量是不安全的,除非用关键字volatile来声明它们,或者用锁保护起来(分解为两个32位操作)</p>\n</li>\n<li><p>volatile变量是一种比sychronized关键字更轻量级的同步机制</p>\n</li>\n<li><p>加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性</p>\n</li>\n<li><p>确保只有单个线程对共享的volatile变量执行写入操作,那么就可以安全地在这些共享的volatile变量上执行“读取-修改-写入”的操作</p>\n</li>\n<li><p>线程封闭(某个对象封闭在一个线程中)包括 Ad-hoc,栈封闭,ThreadLocal类</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">线程封闭:线程封闭的对象只能由一个线程拥有,对象被封闭在该线程中,并且只能由这个线程修改</div><div class=\"line\"></div><div class=\"line\">只读共享:在没有额外同步的情况下,共享的只读对象可以由多个线程并发访问,但任何线程都不能修改它。共享的只读对象包括不可变对象和事实不可变对象</div><div class=\"line\"></div><div class=\"line\">线程安全共享:线程安全的对象在其内部实现同步,因此多个线程可以通过对象的公有接口进行访问而不需要进一步的同步</div><div class=\"line\"></div><div class=\"line\">保护对象:被保护的对象只能通过持有特定的锁来访问。保护对象包括封装在其他线程安全对象中的对象,以及已发布的并且由某个特定锁保护的对象</div></pre></td></tr></table></figure>\n</li>\n</ol>\n<h1 id=\"对象的组合\"><a href=\"#对象的组合\" class=\"headerlink\" title=\"对象的组合\"></a>对象的组合</h1><ul>\n<li>深拷贝与浅拷贝,举例说明:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,<br>A2 中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。</li>\n</ul>\n<h1 id=\"基础构建模块\"><a href=\"#基础构建模块\" class=\"headerlink\" title=\"基础构建模块\"></a>基础构建模块</h1><ul>\n<li><p>迭代器与ConcurrentModificationException,在迭代期间对容器加锁或者“克隆”容器,并在副本上进行迭代</p>\n</li>\n<li><p>通过并发容器(ConcurrentHashMap等)来代替同步容器(synchronizedMap包装的),可以极大地提高伸缩性并降低风险</p>\n</li>\n<li><p>ConcurrentHashMap并不是将每个方法都在同一个锁上同步并使得每次只能有一个线程访问容器,而是使用一种粒度更细的加锁机制来实现更大程度的共享,这种机制称为分段锁(Lock Striping),在这种机制中,任意数量的读取线程可以并发地访问Map,执行读取操作的线程和执行写入操作的线程可以并发地访问Map,并且一定数量的写入线程可以并发地修改Map。ConcurrentHashMap带来的结果是,在并发访问环境下将实现更高的吞吐量,而在单线程环境中只损失非常小的性能</p>\n</li>\n<li><p>CopyOnWriteArrayList 用于替代同步List,写入时复制(Copy-on-write)在每次修改时,都会创建并重新发布一个新的容器副本,从而实现可变性</p>\n</li>\n<li><p>阻塞队列(BlockingQueue,生产者-消费者模式)提供了可阻塞的put和take方法,以及支持定时的offer和poll方法(报错后可执行其他);类库中其他多种实现 LinkedBlockingQueue和ArrayBlockingQueue是FIFO队列,PriorityBlockingQueue是按优先级排序的队列,SynchronousQueue不会为队列中元素维护存储空间,直接交付工作,从而降低了将数据从生产者移动到消费者的延迟</p>\n</li>\n<li><p>双端队列和工作密取:每个消费者都有各自的双端队列,如果一个消费者完成了自己双端队列中的全部工作,那么他可以从其他消费者双端队列末尾秘密地获取工作。工作密取非常适用于既是消费者也是生产者问题,当执行某个工作时可能导致出现更多的工作</p>\n</li>\n<li><p>闭锁可以延迟线程的进度直到其到达终止状态,CountDownLatch是一种灵活的闭锁实现</p>\n</li>\n<li><p>FutureTask可以用做闭锁</p>\n</li>\n<li><p>计数信号量用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量</p>\n<blockquote>\n<p>信号量(Semaphore)的用途,1. 二值信号量,互斥体(mutex) 2. 实现资源池 3.有界阻塞容器</p>\n</blockquote>\n</li>\n<li>栅栏与闭锁区别在于,所有线程必须同时到达栅栏位置,才能继续执行(闭锁是ABCD全部并行执行完毕后,E执行;栅栏是ABCD全部准备好后,一起并发执行)</li>\n</ul>\n<h1 id=\"任务执行\"><a href=\"#任务执行\" class=\"headerlink\" title=\"任务执行\"></a>任务执行</h1><ol>\n<li><p>在生产环境中,为每个任务分配一个线程存在缺陷,避免无限制创建线程,尽量少使用newCachedThreadPool</p>\n</li>\n<li><p>线程池的创建,调用Executors中的静态工厂方法</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">newFixedThreadPool: 每当提交一个任务是就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化(异常的,会补充线程)</div><div class=\"line\"></div><div class=\"line\">newCachedThreadPool:可缓存线程池,多了回收,少了添加,规模没有任何限制</div><div class=\"line\"></div><div class=\"line\">newSingleThreadExecutor:单线程的Executor,确保依照任务在队列中的顺序来串行执行</div><div class=\"line\"></div><div class=\"line\">newScheduledThreadPool:创建固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer</div></pre></td></tr></table></figure>\n</li>\n<li><p>有关延迟任务与周期任务:Timer在执行所有定时任务时只会创建一个线程,如果某个任务的执行时间过长,那么将破坏其他TimerTask的定时准确性,而newScheduledThreadPool线程池可以弥补这个缺陷,提供多个线程来执行</p>\n</li>\n<li><p>Executor执行的任务有4个生命周期阶段:创建,提交,开始和完成。已提交但尚未开始的任务可以取消,但对于那些已经开始执行的任务,只有当它们能响应中断时,才能取消</p>\n</li>\n<li><p>为任务设置时效,在支持时间限制的Future.get中支持这种需求,当结果可用时,立即返回,如果在指定时限内没有计算出结果,将抛出TimeoutException</p>\n</li>\n<li><p>Executor任务执行框架将任务提交与执行策略解耦开来,同时还支持多种不同类型的执行策略</p>\n</li>\n</ol>\n<h1 id=\"取消与关闭\"><a href=\"#取消与关闭\" class=\"headerlink\" title=\"取消与关闭\"></a>取消与关闭</h1><ol>\n<li>线程中断是一种协作机制,线程可以通过这种机制来通知另一个线程,告诉它在合适的时候或者可能的情况下停止当前工作,并转而执行其他工作;通常,中断是实现取消的最合理方式</li>\n<li>每个线程都有一个boolean类型的中断状态,在中断线程时,这个线程中断状态将被设置为true,列举Thread中有关<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">interrupt:中断目标线程</div><div class=\"line\"></div><div class=\"line\">isInterrupted: 返回目标线程的中断状态</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">static</span> interrupted:清除当前线程的中断状态,返回它之前的值</div></pre></td></tr></table></figure>\n</li>\n</ol>\n<h1 id=\"线程池的使用\"><a href=\"#线程池的使用\" class=\"headerlink\" title=\"线程池的使用\"></a>线程池的使用</h1><ol>\n<li><p>使用ThreadLocal的任务:只有当线程本地值的生命周期受限于任务的生命周期时,在线程池的线程中使用ThreadLocal才有意义,而在线程池的线程中不应该使用ThreadLocal在任务之间传递值</p>\n</li>\n<li><p>线程饥饿死锁:线程池中的任务需要无限期等待一些必须由池中其他任务才能提供的资源或条件,例如某个任务等待另一个任务的返回值或执行结果,那么除非线程池足够大,否则将发生线程饥饿死锁</p>\n</li>\n<li><p>设置线程池的大小:考虑部署的系统有多少个CPU;多大内存;任务是计算密集型;I/O密集型还是两者皆可;比如计算密集型任务,线程池大小为cpu数+1能实现最优,I/O密集型线程池的规模可以更大一些</p>\n</li>\n<li><p>若默认的执行策略,如newCachedThreadPool,newFixedThreadPool,newScheduledThreadExecutor 不能满足需求,可以通过ThreadPoolExecutor的构造函数来实例化一个对象</p>\n</li>\n<li><p>调用构造函数后再定制ThreadPoolExecutor,可以通过Setter来修改;如果Executor是通过Executors中的某个工厂方法创建的,那么可以将结果的类型转换为ThreadPoolExecutor以访问设置器</p>\n</li>\n<li><p>ThreadPoolExecutor是可扩展的,它提供了几个可以在子类化中改写的方法:beforeExecute,afterExecute,terminated</p>\n</li>\n<li><p>如果需要提交一个任务集并等待它们完成,那么可以使用ExecutorService.invokeAll,并且在所有任务都执行完成后调用CompletionService来获取结果</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">CompletionService<Integer> completionService = <span class=\"keyword\">new</span> ExecutorCompletionService<Integer>(executor);</div><div class=\"line\"><span class=\"comment\">//向线程池提交任务</span></div><div class=\"line\">completionService.submit(<span class=\"keyword\">new</span> Runnable();</div><div class=\"line\">completionService.take().get();</div></pre></td></tr></table></figure>\n</li>\n</ol>\n<h1 id=\"避免活跃性危险(有关死锁)\"><a href=\"#避免活跃性危险(有关死锁)\" class=\"headerlink\" title=\"避免活跃性危险(有关死锁)\"></a>避免活跃性危险(有关死锁)</h1><ol>\n<li><p>死锁的避免与诊断:支持定时的锁,通过JVM线程转储信息来分析死锁</p>\n</li>\n<li><p>Thread API中定义的线程优先级只是作为线程调度的参考,其中定义了10个优先级,JVM根据需要将它们映射到操作系统的调度优先级,这种映射是于特定平台相关的</p>\n</li>\n<li><p>避免使用线程优先级,因为这会增加平台依赖性,并可能导致活跃性问题,在大多数并发应用程序中,都可以使用默认的线程优先级</p>\n</li>\n<li><p>最常见的活跃性故障就是锁顺序死锁,在设计时应该避免产生锁顺序死锁,确保线程在获取多个锁时采用一致的顺序,最好的解决方法是在程序中始终使用开放调用(调用某个方法时不需要持有锁),这将大大减少需要同时持有多个锁的地方</p>\n</li>\n</ol>\n<h1 id=\"性能和可伸缩性\"><a href=\"#性能和可伸缩性\" class=\"headerlink\" title=\"性能和可伸缩性\"></a>性能和可伸缩性</h1><p>1.可伸缩性指的是增加计算资源时(例如CPU,内存,存储容量,或I/O带宽),程序的吞吐量或者处理能力能相应地增加</p>\n<p>2.在所有并发程序中都包含一些串行部分,如果你认为在程序中不存在串行部分,那么可以在仔细检查一遍<br>3.线程引入开销:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">上下文切换:若可运行的线程数大于CPU的数量,那么操作系统会将某个正在运行的线程调度出来,从而使其他线程能够使用CPU,导致一次上下文切换</div><div class=\"line\">内存同步:区分有竞争的同步和无竞争的同步非常重要</div><div class=\"line\">阻塞:当在锁上发生竞争时,竞争失败的线程肯定会阻塞</div></pre></td></tr></table></figure></p>\n<ol>\n<li><p>在并发程序中,对可伸缩性的最主要威胁就是独占方式的资源锁。三种方式可以降低锁的竞争程度</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">减少锁的持有时间 :缩小锁的范围</div><div class=\"line\">降低锁的请求频率 :减小锁的粒度(锁分解和锁分段)</div><div class=\"line\">使用带有协调机制的独占锁,这些机制允许更高的并发性,比如ReadWriteLock实现一种在多个读取操作以及单个写入操作情况下的加锁规则;原子变量</div></pre></td></tr></table></figure>\n</li>\n<li><p>锁分段:锁分解技术进一步扩展为对一组独立对象上的锁进行分解,这种情况被称为锁分段,例如ConcurrentHashMap的实现中使用了一个包含16个锁的数组,每个锁保护所有散列通的1/16</p>\n</li>\n<li><p>监测CPU的利用率,没有得到充分利用的原因一般包括:负载不充足,I/O密集,外部限制(数据库或web服务),锁竞争</p>\n</li>\n</ol>\n<h1 id=\"并发程序测试\"><a href=\"#并发程序测试\" class=\"headerlink\" title=\"并发程序测试\"></a>并发程序测试</h1><ol>\n<li><p>并发测试大致分为两类:安全性测试,活跃性测试(相关的是性能测试,包括吞吐量,响应性,可伸缩性)</p>\n</li>\n<li><p>总结:并发程序的许多故障模式都是一些低概率事件,它们对于执行时序,负载情况以及其他难以重现的条件都非常敏感,而且在测试程序中还会引入额外的同步或执行时序限制,用java编写的程序在测试起来更加困难,因为动态编译,垃圾回收以及自动优化等操作都会影响与时间相关的测试结果,因此我们需要将传统的测试技术与代码审查和自动化分析工具结合起来</p>\n</li>\n</ol>\n<h1 id=\"显式锁\"><a href=\"#显式锁\" class=\"headerlink\" title=\"显式锁\"></a>显式锁</h1><ol>\n<li>在Java5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile,Java5.0增加了一种新的机制ReentrantLock是内置加锁机制不适用时的一种高级功能</li>\n<li><p>使用ReentrantLock来保护对象状态,代码如下:必须在finally块中释放锁</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Lock lock = <span class=\"keyword\">new</span> ReentrantLock();</div><div class=\"line\">lock.lock();</div><div class=\"line\"><span class=\"keyword\">try</span> {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"更新对象状态\"</span>);</div><div class=\"line\"> System.out.println(<span class=\"string\">\"捕获异常,并在必要时恢复不变形条件\"</span>);</div><div class=\"line\">} <span class=\"keyword\">finally</span> {</div><div class=\"line\"> lock.unlock();</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n<li><p>与内置加锁机制不同的是,Lock提供了一种无条件的,可轮询的,定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显式的</p>\n</li>\n<li>在一些内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具。当需要一些高级功能时才应该使用ReentrantLock,这些功能包括:可定时的,可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized</li>\n<li>有关ReadWriteLock读-写锁:允许多个读操作同时进行,但每次只允许一个写操作,ReentrantReadWriteLock为这两种锁都提供了可重入的加锁定义</li>\n</ol>\n<h1 id=\"构建自定义的同步工具\"><a href=\"#构建自定义的同步工具\" class=\"headerlink\" title=\"构建自定义的同步工具\"></a>构建自定义的同步工具</h1><p>1.状态依赖性的管理:当前提条件未满足时,依赖状态的操作可以抛出一个异常或者返回一个错误状态(使其成为调用者的一个问题),也可以保持阻塞直到对象进入正确的状态</p>\n<ol>\n<li><p>条件队列API中发出通知的方法,即notify和notifyAll。在调用notify时,JVM会从这个条件队列上等待的多个线程中选择一个来唤醒,而调用notifyAll则会唤醒所有在这个条件队列上等待的线程,并且发出通知的线程应该尽快地释放锁,从而确保正在等待的线程尽可能快地解除阻塞</p>\n</li>\n<li><p>只有同时满足以下两个条件时,才能用单一的notify而不是notifyAll: 所有等待线程的类型都相同<br>单进单出</p>\n</li>\n<li><p>有关显式的Condition对象:Lock比内置加锁提供了更为丰富的功能,Condition同样比内置条件队列提供了更丰富的功能,在每个锁上可存在多个等待,条件等待可以是可中断的或不可中断的,基于时限的等待,以及公平的或非公平的队列操作</p>\n</li>\n<li><p>在使用显式的Condition和内置条件队列之间进行选择时,与在ReentrantLock和synchronized之间进行选择是一样的,如果需要一些高级功能,例如使用公平的队列操作或者在每个锁上对应多个等待线程集,那么应该优先使用Condition而不是内置条件队列</p>\n</li>\n<li><p>有关AbstractQueuedSynchronizer(AQS):是一个用于构建锁和同步器的框架,许多同步器都可以通过AQS很容易并且高效地构造出来,包括ReentrantLock,Semaphore,CountDownLatch,ReetrantReadWriteLock,SynchronousQueue,FutureTask</p>\n</li>\n<li><p>小结:有时候现有的库类不能提供足够的功能,在这种情况下,可以使用内置的条件队列,显式的Condition对象或者AbstractQueuedSynchronizer来构建自己的同步器</p>\n</li>\n</ol>\n<h1 id=\"原子变量与非阻塞同步机制\"><a href=\"#原子变量与非阻塞同步机制\" class=\"headerlink\" title=\"原子变量与非阻塞同步机制\"></a>原子变量与非阻塞同步机制</h1><p>1.硬件对并发的支持:比较并交换(CAS),Java5.0后引入底层的支持,原子变量中使用了这些底层的JVM支持为数字类型和引用类型提供一种高效的CAS操作,而在java.util.concurrent中的大多数类在实现时则直接或间接地使用了这些原子变量类</p>\n<p>2.原子变量是一种“更好的volatile”:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">有关volatile:</div><div class=\"line\"></div><div class=\"line\"><span class=\"number\">1.</span> 不要将volatile用在getAndOperate场合,仅仅set或者get的场景是适合volatile的</div><div class=\"line\"></div><div class=\"line\"><span class=\"number\">2.</span> 内存屏蔽的概念,是一个CPU指令,告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行,另一个作用是强制更新一次不同CPU的缓存</div><div class=\"line\"></div><div class=\"line\"><span class=\"number\">3.</span> volatile与内存屏蔽的关系:从Load到store到内存屏障,一共<span class=\"number\">4</span>步,其中最后一步jvm让这个最新的变量的值在所有线程可见,但中间的步骤是不安全的,非原子性</div><div class=\"line\"></div><div class=\"line\"><span class=\"number\">4.</span> volatile保证对线程的可见性,但不保证原子性</div><div class=\"line\"></div><div class=\"line\">原子变量具有原子性和可变性是因为使用到CAS指令,结合volatile</div></pre></td></tr></table></figure></p>\n<ol>\n<li><p>在中低程度的竞争下,原子变量能提供更高的可伸缩性,而在高强度的竞争下,锁能够更有效地避免竞争。但实际情况中,原子变量在可伸缩性上要高于锁</p>\n</li>\n<li><p>构建非阻塞算法的技巧在于:将执行原子修改的范围缩小到单个变量上</p>\n</li>\n<li><p>非阻塞算法通过底层的并发原语(CAS)来维持线程的安全性,这些底层的原语通过原子变量类向外公开。</p>\n</li>\n</ol>\n<h1 id=\"java内存模型\"><a href=\"#java内存模型\" class=\"headerlink\" title=\"java内存模型\"></a>java内存模型</h1><ol>\n<li>Java并发注解</li>\n</ol>\n<ul>\n<li>类注解(@Immutable,@ThreadSafe,@NotThreadSafe)只是说明作用</li>\n<li>域注解</li>\n<li>方法注解(@GuardedBy(lock)这个方法被哪个锁保护着)</li>\n</ul>\n<ol>\n<li><p>有关静态域:静态初始化期间,内存写入操作将自动对所有线程可见,因此无论是在被构造期间还是被引用时,静态初始化的对象都不需要显式的同步</p>\n</li>\n<li><p>小结:Java内存模型说明了某个线程的内存操作在哪些情况下对于其他线程是可见的,其中包括确保这些操作是按照一种Happens-Before的偏序关系进行排序,而这种关系是基于内存操作和同步操作等级别来定义的,如果缺少充足的同步,那么当线程访问共享数据时,会发生一些非常奇怪的问题,然而使用@GuardedBy和安全发布,即使不考虑Happens-Before底层细节,也能确保线程安全性</p>\n</li>\n</ol>\n"},{"title":"线程池的使用","url":"https://yangzhiw.github.io/2017/02/27/线程池的使用/","content":"<h1 id=\"线程池\"><a href=\"#线程池\" class=\"headerlink\" title=\"线程池\"></a>线程池</h1><h2 id=\"为什么要用线程池\"><a href=\"#为什么要用线程池\" class=\"headerlink\" title=\"为什么要用线程池:\"></a>为什么要用线程池:</h2><p>1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。<br>2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。</p>\n<p>Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。</p>\n<h2 id=\"重要的类\"><a href=\"#重要的类\" class=\"headerlink\" title=\"重要的类\"></a>重要的类</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">ExecutorServcie <span class=\"comment\">//真正的线程池接口。</span></div><div class=\"line\">ScheduledExecutorService\t <span class=\"comment\">//能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。</span></div><div class=\"line\">ThreadPoolExecutor <span class=\"comment\">//ExecutorService的默认实现。</span></div><div class=\"line\">ScheduledThreadPoolExecutor <span class=\"comment\">//继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现</span></div></pre></td></tr></table></figure>\n<h2 id=\"线程池工具类\"><a href=\"#线程池工具类\" class=\"headerlink\" title=\"线程池工具类\"></a>线程池工具类</h2><p>要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。<br><strong>1. newSingleThreadExecutor</strong><br>创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。<br><strong>2. newFixedThreadPool</strong><br>创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。<br><strong>3. newCachedThreadPool</strong><br>创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,<br>那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。<br><strong>4. newScheduledThreadPool</strong><br>创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。</p>\n"},{"title":"设计模式之装饰者模式","url":"https://yangzhiw.github.io/2017/02/05/使用heroku免费部署Java应用/设计模式之装饰者模式/","content":""},{"title":"设计模式之观察者模式","url":"https://yangzhiw.github.io/2017/01/21/设计模式之观察者模式/","content":"<h1 id=\"定义\"><a href=\"#定义\" class=\"headerlink\" title=\"定义\"></a>定义</h1><p>在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都全部受到通知并自动更新。</p>\n<h2 id=\"要点\"><a href=\"#要点\" class=\"headerlink\" title=\"要点\"></a>要点</h2><ul>\n<li>使用此模式时,你可从被观察者处推(push)或拉(pull)数据。</li>\n<li>有多个观察者时,不可以依赖特定的通知次序。</li>\n<li>Java有多个观察者模式的实现,包括了通用的java.util.Observable,要注意这种实现带来的一些问题</li>\n</ul>\n"},{"title":"并发编程之多线程","url":"https://yangzhiw.github.io/2017/01/19/并发编程之多线程/","content":"<h1 id=\"线程安全\"><a href=\"#线程安全\" class=\"headerlink\" title=\"线程安全\"></a>线程安全</h1><h2 id=\"概念\"><a href=\"#概念\" class=\"headerlink\" title=\"概念\"></a>概念</h2><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"number\">1</span>、当多个线程访问访问某一个类(对象或方法)时,这个类或对象或方法始终能表现出正确的行为或我们想要的结果,那么这个类(对象或方法)</div><div class=\"line\">就是线程安全的。</div><div class=\"line\"><span class=\"number\">2</span>、synchronized:可以在任意的对象及方法上加锁,而加锁的这段代码称之为互斥区或者临界区。</div></pre></td></tr></table></figure>\n<h1 id=\"线程和锁\"><a href=\"#线程和锁\" class=\"headerlink\" title=\"线程和锁\"></a>线程和锁</h1><p>多个线程多个锁:多个线程,每个线程都可以拿到自己指定的锁,分别获得锁之后,执行synchronized方法体的内容。</p>\n<h2 id=\"代码示例\"><a href=\"#代码示例\" class=\"headerlink\" title=\"代码示例\"></a>代码示例</h2><p>两个线程t1,t2分别依次start,访问两个对象的synchronized修饰的printNum方法,Code如下:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * 关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁,</div><div class=\"line\"> * 所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),</div><div class=\"line\"> * </div><div class=\"line\"> * 在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)。</div><div class=\"line\"> * <span class=\"doctag\">@author</span> xujin</div><div class=\"line\"> *</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">MultiThread</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">int</span> num = <span class=\"number\">0</span>;</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">synchronized</span> <span class=\"keyword\">void</span> <span class=\"title\">printNum</span><span class=\"params\">(String tag)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"keyword\">if</span> (tag.equals(<span class=\"string\">\"a\"</span>)) {</div><div class=\"line\"> num = <span class=\"number\">100</span>;</div><div class=\"line\"> System.out.println(<span class=\"string\">\"tag a, set num over!\"</span>);</div><div class=\"line\"> Thread.sleep(<span class=\"number\">1000</span>);</div><div class=\"line\"> } <span class=\"keyword\">else</span> {</div><div class=\"line\"> num = <span class=\"number\">200</span>;</div><div class=\"line\"> System.out.println(<span class=\"string\">\"tag b, set num over!\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> System.out.println(<span class=\"string\">\"tag \"</span> + tag + <span class=\"string\">\", num = \"</span> + num);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"comment\">// 注意观察run方法输出顺序</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span>{</div><div class=\"line\"> <span class=\"comment\">// 两个不同的对象</span></div><div class=\"line\"> <span class=\"keyword\">final</span> MultiThread m1 = <span class=\"keyword\">new</span> MultiThread();</div><div class=\"line\"> <span class=\"keyword\">final</span> MultiThread m2 = <span class=\"keyword\">new</span> MultiThread();</div><div class=\"line\"> Thread t1 = <span class=\"keyword\">new</span> Thread(<span class=\"keyword\">new</span> Runnable() {</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> m1.printNum(<span class=\"string\">\"a\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> });</div><div class=\"line\"> Thread t2 = <span class=\"keyword\">new</span> Thread(<span class=\"keyword\">new</span> Runnable() {</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> m2.printNum(<span class=\"string\">\"b\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> });</div><div class=\"line\"> t1.start();</div><div class=\"line\"> t2.start();</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>执行结果如下:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">tag a, set num over!</div><div class=\"line\">tag b, set num over!</div><div class=\"line\">tag b, num = <span class=\"number\">200</span></div><div class=\"line\">tag a, num = <span class=\"number\">100</span></div></pre></td></tr></table></figure></p>\n<p>关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁,<br>所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock)</p>\n<p>如果,在静态方法上printNum()加一个synchronized关键字修饰的话,那这个线程调用printNum()获得锁,就是这个类级别的锁。这是时候无论你实例化出多少个对象m1,m2都是没有任何关系的。<br>这样测试的结果是<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">tag a, set num over!</div><div class=\"line\">tag a, num = <span class=\"number\">100</span></div><div class=\"line\">tag b, set num over!</div><div class=\"line\">tag b, num = <span class=\"number\">200</span></div></pre></td></tr></table></figure></p>\n<p>小结:<br>关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法当做锁,所以示例中代码中的哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法对象的锁,也就是Lock,两个对象,线程获得的就是两个不同的锁,他们互不影响。<br>有一种情况则是相同的锁,即在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁独占.class类。</p>\n<h2 id=\"脏读\"><a href=\"#脏读\" class=\"headerlink\" title=\"脏读\"></a>脏读</h2><p>业务整体需要使用完整的synchronized,保持业务的原子性。</p>\n<p>在我们对对象中的一个方法加锁的时候,需要考虑业务的或程序的整体性,也就是为程序中的set和get方法同时加锁synchronized同步关键字,保证业务的(service层)的原子性,不然会出现数据错误,脏读。</p>\n<h2 id=\"synchronized的重入\"><a href=\"#synchronized的重入\" class=\"headerlink\" title=\"synchronized的重入\"></a>synchronized的重入</h2><h3 id=\"什么是synchronized的重入锁\"><a href=\"#什么是synchronized的重入锁\" class=\"headerlink\" title=\"什么是synchronized的重入锁\"></a>什么是synchronized的重入锁</h3><p>synchronized,它拥有强制原子性的内置锁机制,是一个重入锁,所以在使用synchronized时,当一个线程请求得到一个对象锁后再次请求此对象锁,可以再次得到该对象锁,就是说在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以拿到锁。<br>当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞</p>\n<p>简单的说:关键字synchronized具有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁的锁后,再次请求此对象时可以再次得到该对象对应的锁。</p>\n<p>这里的对象锁只有一个,就是child对象的锁,当执行child.doSomething时,该线程获得child对象的锁,在doSomething方法内执行doAnotherThing时再次请求child对象的锁,因为synchronized是重入锁,所以可以得到该锁,继续在doAnotherThing里执行父类的doSomething方法时第三次请求child对象的锁,同理可得到,如果不是重入锁的话,那这后面这两次请求锁将会被一直阻塞,从而导致死锁。<br>所以在Java内部,同一线程在调用自己类中其他synchronized方法/块或调用父类的synchronized方法/块都不会阻碍该线程的执行,就是说同一线程对同一个对象锁是可重入的,而且同一个线程可以获取同一把锁多次,也就是可以多次重入。因为java线程是基于“每线程(per-thread)”,而不是基于“每调用(per-invocation)”的(java中线程获得对象锁的操作是以每线程为粒度的,per-invocation互斥体获得对象锁的操作是以每调用作为粒度的)</p>\n<p>其实现方法是为每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁。</p>\n<p>注意就是不要使用String的常量加锁,会出现死循环问题。</p>\n<h3 id=\"锁对象的改变问题\"><a href=\"#锁对象的改变问题\" class=\"headerlink\" title=\"锁对象的改变问题:\"></a>锁对象的改变问题:</h3><p>当使用一个对象进行加锁的时候,要注意对象本身发生变化的时候,那么持有的锁就不同。如果对象本身不发生改变,那么依然是同步的,即使是对象的属性发生了变化。</p>\n<p>同一对象属性的修改不会影响锁的情况</p>\n<p>如:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">ModifyLock</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> String name;</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">int</span> age;</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> String <span class=\"title\">getName</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> name;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">setName</span><span class=\"params\">(String name)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">this</span>.name = name;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">int</span> <span class=\"title\">getAge</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> age;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">setAge</span><span class=\"params\">(<span class=\"keyword\">int</span> age)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">this</span>.age = age;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">synchronized</span> <span class=\"keyword\">void</span> <span class=\"title\">changeAttributte</span><span class=\"params\">(String name, <span class=\"keyword\">int</span> age)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"当前线程 : \"</span> + Thread.currentThread().getName() + <span class=\"string\">\" 开始\"</span>);</div><div class=\"line\"> <span class=\"keyword\">this</span>.setName(name);</div><div class=\"line\"> <span class=\"keyword\">this</span>.setAge(age);</div><div class=\"line\"> System.out.println(<span class=\"string\">\"当前线程 : \"</span> + Thread.currentThread().getName() + <span class=\"string\">\" 修改对象内容为: \"</span> + <span class=\"keyword\">this</span>.getName() + <span class=\"string\">\", \"</span></div><div class=\"line\"> + <span class=\"keyword\">this</span>.getAge());</div><div class=\"line\"> Thread.sleep(<span class=\"number\">2000</span>);</div><div class=\"line\"> System.out.println(<span class=\"string\">\"当前线程 : \"</span> + Thread.currentThread().getName() + <span class=\"string\">\" 结束\"</span>);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">final</span> ModifyLock modifyLock = <span class=\"keyword\">new</span> ModifyLock();</div><div class=\"line\"> Thread t1 = <span class=\"keyword\">new</span> Thread(<span class=\"keyword\">new</span> Runnable() {</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> modifyLock.changeAttributte(<span class=\"string\">\"许进\"</span>, <span class=\"number\">25</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }, <span class=\"string\">\"t1\"</span>);</div><div class=\"line\"> Thread t2 = <span class=\"keyword\">new</span> Thread(<span class=\"keyword\">new</span> Runnable() {</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> modifyLock.changeAttributte(<span class=\"string\">\"李四X\"</span>, <span class=\"number\">21</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }, <span class=\"string\">\"t2\"</span>);</div><div class=\"line\"> t1.start();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> Thread.sleep(<span class=\"number\">100</span>);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> t2.start();</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>运行结果:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">当前线程 : t1 开始</div><div class=\"line\">当前线程 : t1 修改对象内容为: 许进, <span class=\"number\">25</span></div><div class=\"line\">当前线程 : t1 结束</div><div class=\"line\">当前线程 : t2 开始</div><div class=\"line\">当前线程 : t2 修改对象内容为: 李四X, <span class=\"number\">21</span></div><div class=\"line\">当前线程 : t2 结束</div></pre></td></tr></table></figure></p>\n"},{"title":"ScheduledThreadPoolExecutor的使用","url":"https://yangzhiw.github.io/2017/01/17/ScheduledThreadPoolExecutor的使用/","content":"<p>Java Executor框架提供了ThreadPoolExecutor类去执行Callable和Runnable任务,这样避免了大量的复杂代码的操作,但是有时你需要定时去执行你的任务,这个时候你就要使用ScheduledThreadPoolExecutor类了。</p>\n<h1 id=\"先写个基本的任务\"><a href=\"#先写个基本的任务\" class=\"headerlink\" title=\"先写个基本的任务\"></a>先写个基本的任务</h1><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Task</span> <span class=\"keyword\">implements</span> <span class=\"title\">Runnable</span></span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"keyword\">private</span> String name;</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"title\">Task</span><span class=\"params\">(String name)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">this</span>.name = name;</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> String <span class=\"title\">getName</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> name;</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span></div><div class=\"line\"> {</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Doing a task during : \"</span> + name + <span class=\"string\">\" - Time - \"</span> + <span class=\"keyword\">new</span> Date());</div><div class=\"line\"> } </div><div class=\"line\"> <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h1 id=\"一段时间后执行\"><a href=\"#一段时间后执行\" class=\"headerlink\" title=\"一段时间后执行\"></a>一段时间后执行</h1><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">ScheduledThreadPoolExecutorExample</span></span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span></div><div class=\"line\"> {</div><div class=\"line\"> ScheduledExecutorService executor = Executors.newScheduledThreadPool(<span class=\"number\">2</span>);</div><div class=\"line\"> Task task1 = <span class=\"keyword\">new</span> Task (<span class=\"string\">\"Demo Task 1\"</span>);</div><div class=\"line\"> Task task2 = <span class=\"keyword\">new</span> Task (<span class=\"string\">\"Demo Task 2\"</span>);</div><div class=\"line\"> </div><div class=\"line\"> System.out.println(<span class=\"string\">\"The time is : \"</span> + <span class=\"keyword\">new</span> Date());</div><div class=\"line\"> </div><div class=\"line\"> executor.schedule(task1, <span class=\"number\">5</span> , TimeUnit.SECONDS);</div><div class=\"line\"> executor.schedule(task2, <span class=\"number\">10</span> , TimeUnit.SECONDS);</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> executor.awaitTermination(<span class=\"number\">1</span>, TimeUnit.DAYS);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> executor.shutdown();</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>The time is : Tue Jan 25 16:14:07 IST 2017<br>Doing a task during : Demo Task 1 - Time - Tue Jan 25 16:14:12 IST 2017<br>Doing a task during : Demo Task 2 - Time - Tue Jan 25 16:14:17 IST 2017</p>\n<h1 id=\"执行任务时间片的形式\"><a href=\"#执行任务时间片的形式\" class=\"headerlink\" title=\"执行任务时间片的形式\"></a>执行任务时间片的形式</h1><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">ScheduledThreadPoolExecutorExample</span></span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span></div><div class=\"line\"> {</div><div class=\"line\"> ScheduledExecutorService executor = Executors.newScheduledThreadPool(<span class=\"number\">1</span>);</div><div class=\"line\"> Task task1 = <span class=\"keyword\">new</span> Task (<span class=\"string\">\"Demo Task 1\"</span>);</div><div class=\"line\"> </div><div class=\"line\"> System.out.println(<span class=\"string\">\"The time is : \"</span> + <span class=\"keyword\">new</span> Date());</div><div class=\"line\"> </div><div class=\"line\"> ScheduledFuture<?> result = executor.scheduleAtFixedRate(task1, <span class=\"number\">2</span>, <span class=\"number\">5</span>, TimeUnit.SECONDS);</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> TimeUnit.MILLISECONDS.sleep(<span class=\"number\">20000</span>);</div><div class=\"line\"> } </div><div class=\"line\"> <span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> executor.shutdown();</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>Output:</p>\n<p>The time is : Tue Jan 25 16:20:12 IST 2017<br>Doing a task during : Demo Task 1 - Time - Tue Jan 25 16:20:14 IST 2017<br>Doing a task during : Demo Task 1 - Time - Tue Jan 25 16:20:19 IST 2017<br>Doing a task during : Demo Task 1 - Time - Tue Jan 25 16:20:24 IST 2017<br>Doing a task during : Demo Task 1 - Time - Tue Jan 25 16:20:29 IST 2017</p>\n"},{"title":"2016、才觉远去,便起怀念","url":"https://yangzhiw.github.io/2016/12/31/才觉远去,便起回忆/","content":"<p> 一年的开始,总是伴着喜庆的色彩。1月份,往往很多公司都要开始准备年会了。作为公司最年轻的团队,也忘记了是哪个家伙想的,让我们年会上唱bigbang的loser😭。我和另外4个小伙伴不幸就被选上了,拼了,就算是为了我们这个团队,依稀的记得的那一晚,我们玩的很嗨。虽然还是在实习阶段,可是我已觉得我早已融入进这个团队了,和他们成为了好朋友。从大三暑期实习开始,我就已经知道我没有寒假和暑假了,这一年的春节,虽然在家里呆的时间也不长。对我来说是不同的,因为我自己可以赚钱了,拿着这些钱给父母买了些东西,可以外婆包红包了就像当初她给我们一样。</p>\n<p> 匆匆茫茫的回到了公司,重新开始了工作。元宵节,和几个大学一起过的,在一个城市,有些同学还是不错的,至少平时我们可以相互发发牢骚。感觉到了3月份,工作才慢慢进入正轨,这个时候的我也开始思考了毕业之后的去向了,思考着是继续留在实习的公司还是去重新找一家,最终考虑的结果是留在这个公司,因为这里有很多我熟悉的人和事。3月末,了解到团队中有些实习生要走了,有要去读研深造的,有要换公司的,在送别聚餐的那一晚,我们很多都喝多了。或许我们都知道有相聚就有离开,但是没想到这才是刚刚开始而已。</p>\n<p> 杭州的4月天是很舒服的,听说一个高中的同桌同学来到了浙大读研,我当初怎么没看出来你还有这个潜力。我们一起在杭州西湖旁边的山上踏着青,记得她说过,还是老同学在一起实在啊。是啊,高中时的那些同学们,我还记的和你们一起奋斗和玩耍的时光啊。五月初,我们团队自驾游去了安吉的天荒坪了,虽然那个周末天气不是很好,但我们还是玩的很开心的。回来的路上,我们在车上把后备箱的几瓶酒在路上全吹掉了,一种宿醉的感觉。</p>\n<p> 想到马上要回到学校,内心还是很激动过的,可能都知道大学四年就剩下这1个多月时间了,同学宿舍之间走动更加的频繁了。时间流逝的总是快的,做毕设、写论文、答辩、拍毕业照、毕业酒会。马上就要毕业了,谁又能想到答辩那天走出教室后,直到现在我都没有再进去过大学教室。是啊,要再见了,我的小伙伴们。</p>\n<p> 6月25号,从南昌来到杭州,其实内心还是很激动的,因为我知道我再也不是实习生了,我马上要转为公司的正式员工了。可是令我想不到的是很多事情都在改变,领导也不再是之前的领导,一年时间真的是习惯了你们的存在(后面在新的一家公司上班时,叫错了几次领导的名字😅)。接下来公司工作环境就变得有些诡异了,当时也没想太多,更深层次的东西我也想不到,只是感觉,这种工作状态还不如之前实习的那个团队,当工作失去激情,离离开也就不远了。好在,我并没有因为这样的状态而颓废,这段时间,本人开了博客,开始写写技术文章,学习新技术以充实自己,这段时间的知识积累,也对我后面找新的工作有了帮助。接下来杭州慢慢开始成为世界上最安全最干净的城市了,因为受全世界关注的G20要在杭州举行了,杭州真的很不错,我喜欢这座城。</p>\n<p> 离开,9月20号,因某些原因,从公司离开。接下来,很多的散伙饭,这让我想起了毕业时的场景,没有不散的宴席,谁会饿着肚子去呐喊,开始准备写简历去迎接新的工作了。面了6家企业,我最终还是选择了感觉最有发展前景的C公司,准备国庆后迎接新的环境。</p>\n<p> 深刻体会来到一家新的企业,都要给时间去适应的。10月基本上也就是去适应公司环境的过程了;公司发展迅速,项目时间安排紧,而这给我带来的影响就是经常加班了。可能是为了缓解压力,11月份公司安排一次团建,是去安吉,顿时有种熟悉的感觉。</p>\n<p> 一年过的真的很快啊,突然就到了一年的最后一个月了,这个月真是工作以来忙碌的一个月啊,就连今天这一年的最后一天,都在公司加班(😂,其实心根本不在状态)。还有就是这个月也是最难忘的,因为我遇到了一个让我心动的女孩,是的,那是心动的感觉。</p>\n<p> 在新的一年里,希望自己能养成看书的习惯吧,然后让自己运动起来,最后希望就是工作轻松些,似乎这也不太实际了,成长总要付出努力和汗水。</p>\n"},{"title":"设计模式之策略模式","url":"https://yangzhiw.github.io/2016/12/31/设计模式之策略模式/","content":"<h2 id=\"定义\"><a href=\"#定义\" class=\"headerlink\" title=\"定义\"></a>定义</h2><p>策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。</p>\n<h2 id=\"原则基础\"><a href=\"#原则基础\" class=\"headerlink\" title=\"原则基础\"></a>原则基础</h2><p>封装变化;多用组合、少用继承;针对接口编程,而不是针对实现编程。</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"></div><div class=\"line\"></div></pre></td></tr></table></figure>"},{"title":"分布式系统","url":"https://yangzhiw.github.io/2016/11/25/分布式系统/","content":"<h1 id=\"高吞吐,高并发,底延迟\"><a href=\"#高吞吐,高并发,底延迟\" class=\"headerlink\" title=\"高吞吐,高并发,底延迟\"></a>高吞吐,高并发,底延迟</h1><h1 id=\"分布式系统提高承载量的基本手段\"><a href=\"#分布式系统提高承载量的基本手段\" class=\"headerlink\" title=\"分布式系统提高承载量的基本手段\"></a>分布式系统提高承载量的基本手段</h1><pre><code>## 分层模型(路由,代理)\n\n 典型的的就是三层结构:接入,逻辑,存储\n\n## 并发模型(多线程,异步)\n 多线程\n 异步回调基于非阻塞的I/O操作(网络和文件)\n\n## 缓冲技术\n## 存储技术(NoSQL)\n</code></pre><h1 id=\"分布式系统在可管理性上造成的问题\"><a href=\"#分布式系统在可管理性上造成的问题\" class=\"headerlink\" title=\"分布式系统在可管理性上造成的问题\"></a>分布式系统在可管理性上造成的问题</h1><pre><code>## 硬件故障率\n\n## 资源利用率优化\n\n## 软件服务内容更新\n\n ## 数据统计和决策\n</code></pre><h1 id=\"解决分布式系统可管理性的基本手段\"><a href=\"#解决分布式系统可管理性的基本手段\" class=\"headerlink\" title=\"解决分布式系统可管理性的基本手段\"></a>解决分布式系统可管理性的基本手段</h1><pre><code>## 目录服务(ZooKeeper)\n\n## 消息队列服务(ActiveMQ、ZeroMQ、Jgroups)\n\n## 事务系统\n\n## 自动部署工具(Docker)\n\n## 日志服务(log4j)\n</code></pre><h1 id=\"分布式系统在开发效率上造成的问题和解决思路\"><a href=\"#分布式系统在开发效率上造成的问题和解决思路\" class=\"headerlink\" title=\"分布式系统在开发效率上造成的问题和解决思路\"></a>分布式系统在开发效率上造成的问题和解决思路</h1>"},{"title":"spring-kafak集成学习","url":"https://yangzhiw.github.io/2016/10/24/spring-kafak集成学习/","content":""},{"title":"Spring MVC拦截器","url":"https://yangzhiw.github.io/2016/09/18/Spring-MVC拦截器/","content":"<h1 id=\"使用场景\"><a href=\"#使用场景\" class=\"headerlink\" title=\"使用场景\"></a>使用场景</h1><p>记录web请求的相关日志,可以做信息监控,统计,分析<br>检查web的访问权限,例如发现用户没有登录后,重定向到登录页面。<br>打开关闭数据库连接–预处理打开,后处理关闭,可以避免所有的业务方法中都编写相似的类。</p>\n<h1 id=\"Spring-MVC的请求流程\"><a href=\"#Spring-MVC的请求流程\" class=\"headerlink\" title=\"Spring MVC的请求流程\"></a>Spring MVC的请求流程</h1><img src=\"/2016/09/18/Spring-MVC拦截器/spring-mvc1.jpg\" alt=\"Spring-MVC请求流程\" title=\"Spring-MVC请求流程\">\n<h1 id=\"HandlerInterceptor接口\"><a href=\"#HandlerInterceptor接口\" class=\"headerlink\" title=\"HandlerInterceptor接口\"></a>HandlerInterceptor接口</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div></pre></td><td class=\"code\"><pre><div class=\"line\">public interface HandlerInterceptor {</div><div class=\"line\"> boolean preHandle(HttpServletRequest request, </div><div class=\"line\"> HttpServletResponse response, </div><div class=\"line\"> Object handler) throws Exception;</div><div class=\"line\"></div><div class=\"line\"> void postHandle(HttpServletRequest request, </div><div class=\"line\"> HttpServletResponse response, </div><div class=\"line\"> Object handler, ModelAndView modelAndView) throws Exception;</div><div class=\"line\"></div><div class=\"line\"> void afterCompletion(HttpServletRequest request, </div><div class=\"line\"> HttpServletResponse response, </div><div class=\"line\"> Object handler, Exception ex) throws Exception;</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>1.preHandle():预处理回调方法,若方法返回值为true,请求继续(调用下一个拦截器或处理器方法);若方法返回值为false,请求处理流程中断,不会继续调用其他的拦截器或处理器方法,此时需要通过response产生响应;<br>2.postHandle():后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时可以通过modelAndView对模型数据进行处理或对视图进行处理<br>3.afterCompletion():整个请求处理完毕回调方法,即在视图渲染完毕时调用</p>\n<h1 id=\"实例:用户登录检查\"><a href=\"#实例:用户登录检查\" class=\"headerlink\" title=\"实例:用户登录检查\"></a>实例:用户登录检查</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">public class LoginInterceptor extends HandlerInterceptorAdapter {</div><div class=\"line\"></div><div class=\"line\"> @Override</div><div class=\"line\"> public boolean preHandle(HttpServletRequest request,</div><div class=\"line\"> HttpServletResponse response,</div><div class=\"line\"> Object handler) throws Exception {</div><div class=\"line\"> if (request.getSession().getAttribute(Constants.USER_SESSION_ATTR) != <span class=\"literal\">null</span>) {</div><div class=\"line\"> return <span class=\"literal\">true</span>;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> response.sendRedirect(<span class=\"string\">\"/\"</span>);</div><div class=\"line\"> return <span class=\"literal\">false</span>;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h1 id=\"配置Interceptor\"><a href=\"#配置Interceptor\" class=\"headerlink\" title=\"配置Interceptor\"></a>配置Interceptor</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">@Configuration</div><div class=\"line\">public class WebMvcConfig extends WebMvcConfigurerAdapter {</div><div class=\"line\"></div><div class=\"line\"> @Override</div><div class=\"line\"> public void addInterceptors(InterceptorRegistry registry) {</div><div class=\"line\"> registry.addInterceptor(new LoginInterceptor())</div><div class=\"line\"> .addPathPatterns(<span class=\"string\">\"/**\"</span>)</div><div class=\"line\"> .excludePathPatterns(<span class=\"string\">\"/account/*\"</span>).excludePathPatterns(<span class=\"string\">\"/\"</span>);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n"},{"title":"codis 配置","url":"https://yangzhiw.github.io/2016/09/18/codis 配置/","content":"<p>@Configuration<br>public class CodisConfiguration {<br> @Value(“${codis.zookeeper.clients}”)<br> private String zkClients;<br> @Value(“${codis.zookeeper.proxyDir}”)<br> private String zkDir;<br> @Value(“${codis.poolConfig.maxIdle}”)<br> private int maxIdle;<br> @Value(“${codis.poolConfig.maxTotal}”)<br> private int maxTotal;</p>\n<pre><code>@Bean\npublic JedisResourcePool jedisResourcePool() {\n JedisPoolConfig poolConfig = new JedisPoolConfig();\n poolConfig.setMaxIdle(maxIdle);\n poolConfig.setMaxTotal(maxTotal);\n poolConfig.setTestOnBorrow(true);\n return RoundRobinJedisPool.create().curatorClient(zkClients, 30000).zkProxyDir(zkDir)\n .poolConfig(poolConfig).build();\n}\n</code></pre><p>}</p>\n"},{"title":"二叉树的遍历","url":"https://yangzhiw.github.io/2016/09/18/二叉树的遍历/","content":"<h1 id=\"中序遍历\"><a href=\"#中序遍历\" class=\"headerlink\" title=\"中序遍历\"></a>中序遍历</h1><p>从树的根节点开始,沿着其左孩子域向下移动,直到某一节点再无左节点,访问这个最左边的节点,接下来再从此节点的右孩子<br>开始进行中序遍历,当右子树遍历完了以后,退回到上一层的未访问节点继续二叉树遍历,直到书中所有节点被访问到为止。</p>\n<h1 id=\"先序遍历\"><a href=\"#先序遍历\" class=\"headerlink\" title=\"先序遍历\"></a>先序遍历</h1><p>对节点的访问时在其左、右子树之前进行的。遍历是从根节点开始的,遇到每个节点时,遍历过程为:<br>访问根节点<br>先序遍历其左子树<br>先序遍历其右子树</p>\n"},{"title":"使用Heroku免费部署Java应用","url":"https://yangzhiw.github.io/2016/08/29/使用heroku免费部署Java应用/","content":"<h1 id=\"简介\"><a href=\"#简介\" class=\"headerlink\" title=\"简介\"></a>简介</h1><p>Heroku是一个支持多种编程语言的云平台即服务。</p>\n<h1 id=\"准备\"><a href=\"#准备\" class=\"headerlink\" title=\"准备\"></a>准备</h1><p>1.注册Herku账号<br>2.在本地安装Java8<br>3.在本地安装Maven3</p>\n<h1 id=\"安装\"><a href=\"#安装\" class=\"headerlink\" title=\"安装\"></a>安装</h1><p>安装本地客户端 Heroku-cli,<a href=\"https://devcenter.heroku.com/articles/heroku-command-line\" target=\"_blank\" rel=\"external\">安装Heroku-cli</a></p>\n<p>然后打开命令行工具登录如:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">>heroku login</div><div class=\"line\">Enter your Heroku credentials.</div><div class=\"line\"><span class=\"attr\">Email:</span> [email protected]</div><div class=\"line\"><span class=\"attr\">Password:</span></div></pre></td></tr></table></figure></p>\n<h1 id=\"部署应用\"><a href=\"#部署应用\" class=\"headerlink\" title=\"部署应用\"></a>部署应用</h1><p>这里我们使用官网给的应用<br>首先克隆git clone <a href=\"https://github.com/heroku/java-getting-started.git\" target=\"_blank\" rel=\"external\">https://github.com/heroku/java-getting-started.git</a><br>cd到项目目录: cd java-getting-started<br>创建应用到Heroku上如:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">> heroku create</div><div class=\"line\">Creating shielded-caverns<span class=\"bullet\">-88393.</span>.. done, stack is cedar<span class=\"bullet\">-14</span></div><div class=\"line\"><span class=\"attr\">http:</span>//shielded-caverns<span class=\"bullet\">-88393.</span>herokuapp.com/ | https://git.heroku.com/shielded-caverns<span class=\"bullet\">-88393.</span>git</div></pre></td></tr></table></figure></p>\n<p>shielded-caverns-88393 这是一个随机的数,可以到keroku的应用列表找到这个应用,然后去修改。</p>\n<h2 id=\"部署应用代码\"><a href=\"#部署应用代码\" class=\"headerlink\" title=\"部署应用代码\"></a>部署应用代码</h2><blockquote>\n<p>git push heroku master</p>\n</blockquote>\n<h2 id=\"访问\"><a href=\"#访问\" class=\"headerlink\" title=\"访问\"></a>访问</h2><blockquote>\n<p>heroku open</p>\n</blockquote>\n<h1 id=\"查看日志\"><a href=\"#查看日志\" class=\"headerlink\" title=\"查看日志\"></a>查看日志</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"attr\">D:</span>\\resource\\java-getting-started>heroku logs --tail</div><div class=\"line\"><span class=\"number\">2016</span><span class=\"bullet\">-08</span><span class=\"bullet\">-29</span>T02:<span class=\"number\">37</span>:<span class=\"number\">19.738508</span>+<span class=\"number\">00</span>:<span class=\"number\">00</span> heroku[api]: Release v2 created by [email protected]</div><div class=\"line\"><span class=\"number\">2016</span><span class=\"bullet\">-08</span><span class=\"bullet\">-29</span>T02:<span class=\"number\">37</span>:<span class=\"number\">19.738508</span>+<span class=\"number\">00</span>:<span class=\"number\">00</span> heroku[api]: Enable Logplex by [email protected]</div><div class=\"line\"><span class=\"number\">2016</span><span class=\"bullet\">-08</span><span class=\"bullet\">-29</span>T02:<span class=\"number\">37</span>:<span class=\"number\">45.907720</span>+<span class=\"number\">00</span>:<span class=\"number\">00</span> heroku[router]: at=info code=H81 desc=<span class=\"string\">\"Blank app\"</span> method=GET path=<span class=\"string\">\"/\"</span> h</div><div class=\"line\">erns<span class=\"bullet\">-88393.</span>herokuapp.com request_id=<span class=\"number\">9872849</span>a-d62c<span class=\"bullet\">-4053</span>-b744-b067e1270c3b fwd=<span class=\"string\">\"45.55.27.82\"</span> dyno= connect</div><div class=\"line\">s=<span class=\"number\">502</span> bytes=</div></pre></td></tr></table></figure>\n<h1 id=\"定义Procfile\"><a href=\"#定义Procfile\" class=\"headerlink\" title=\"定义Procfile\"></a>定义Procfile</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"attr\">web:</span> java -jar target/helloworld.jar</div></pre></td></tr></table></figure>\n<h1 id=\"本地运行\"><a href=\"#本地运行\" class=\"headerlink\" title=\"本地运行\"></a>本地运行</h1><h2 id=\"安装依赖\"><a href=\"#安装依赖\" class=\"headerlink\" title=\"安装依赖\"></a>安装依赖</h2><p>mvn clean install</p>\n<h2 id=\"运行\"><a href=\"#运行\" class=\"headerlink\" title=\"运行\"></a>运行</h2><p>heroku local web<br>打开浏览器输入localhost:5000即可访问</p>\n<h1 id=\"其他服务提供\"><a href=\"#其他服务提供\" class=\"headerlink\" title=\"其他服务提供\"></a>其他服务提供</h1><p>默认情况下,Heroku能够显示1500行日志。然而,它提供完整的日志流作为服务——和几个插件提供商所写的日志服务,<br>提供诸如日志持久性、搜索和电子邮件和短信提醒。</p>\n<p>下面,我们将提供一个日志插件,Papertrail。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"attr\">D:</span>\\resource\\java-getting-started>heroku addons:create papertrail</div><div class=\"line\">Creating papertrail on shielded-caverns<span class=\"bullet\">-88393.</span>.. !</div><div class=\"line\"> ! Please verify your account to install this add-on plan (please enter a credit card) For more information, see</div><div class=\"line\"> ! https://devcenter.heroku.com/categories/billing Verify now at https://heroku.com/verify</div></pre></td></tr></table></figure></p>\n<p>这里提示要在heroku输入一个银行卡的信息。先不做这个演示了</p>\n<p>使用heroku addons可以查看已经装好的插件服务。</p>\n<h1 id=\"heroku终端\"><a href=\"#heroku终端\" class=\"headerlink\" title=\"heroku终端\"></a>heroku终端</h1><p>heroku run bash</p>\n<h1 id=\"设置变量\"><a href=\"#设置变量\" class=\"headerlink\" title=\"设置变量\"></a>设置变量</h1><p>heroku config:set ENERGY=”20 GeV”<br>查看变量<br>heroku config</p>\n<h1 id=\"使用数据库\"><a href=\"#使用数据库\" class=\"headerlink\" title=\"使用数据库\"></a>使用数据库</h1><p>数据库的使用也是需要安装服务的,详情见<br><a href=\"https://elements.heroku.com/addons#data-stores,""\" target=\"_blank\" rel=\"external\">安装数据库插件</a></p>\n"},{"title":"Spring Boot 中的统一异常处理","url":"https://yangzhiw.github.io/2016/08/28/Spring-Boot-中的统一异常处理/","content":"<p>Spring Boot中默认带了error的映射,但是这个错误页面显示给用户并不是很友好。</p>\n<h1 id=\"统一异常处理\"><a href=\"#统一异常处理\" class=\"headerlink\" title=\"统一异常处理\"></a>统一异常处理</h1><h2 id=\"通过使用-ControllerAdvice定义统一异常处理的类,而不是在每个Controller中逐个定义。\"><a href=\"#通过使用-ControllerAdvice定义统一异常处理的类,而不是在每个Controller中逐个定义。\" class=\"headerlink\" title=\"通过使用@ControllerAdvice定义统一异常处理的类,而不是在每个Controller中逐个定义。\"></a>通过使用@ControllerAdvice定义统一异常处理的类,而不是在每个Controller中逐个定义。</h2><p>@ExceptionHandler用来定义函数针对的函数类型,最后将Exception对象和请求URL映射到URL中。</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">@ControllerAdvice</div><div class=\"line\">class ExceptionTranslator {</div><div class=\"line\"></div><div class=\"line\"> public static final String DEFAULT_ERROR_VIEW = <span class=\"string\">\"error\"</span>;</div><div class=\"line\"></div><div class=\"line\"> @ExceptionHandler(value = Exception.class)</div><div class=\"line\"> public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {</div><div class=\"line\"> ModelAndView mav = new ModelAndView();</div><div class=\"line\"> mav.addObject(<span class=\"string\">\"exception\"</span>, e);</div><div class=\"line\"> mav.addObject(<span class=\"string\">\"url\"</span>, req.getRequestURL());</div><div class=\"line\"> mav.setViewName(DEFAULT_ERROR_VIEW);</div><div class=\"line\"> return mav;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"实现error-html页面展示\"><a href=\"#实现error-html页面展示\" class=\"headerlink\" title=\"实现error.html页面展示\"></a>实现error.html页面展示</h2><p>在templates目录下创建error.html。<br>例如:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><!DOCTYPE html<span class=\"string\">> </span></div><div class=\"line\"><html> </div><div class=\"line\"><head lang=\"en\"> </div><div class=\"line\"> <meta charset=\"UTF-8\" /></div><div class=\"line\"> <title>统一异常处理</title></div><div class=\"line\"></head> </div><div class=\"line\"><body> </div><div class=\"line\"> <h1>Error Handler</h1></div><div class=\"line\"> <div th:text=\"${url}\"></div></div><div class=\"line\"> <div th:text=\"${exception.message}\"></div></div><div class=\"line\"></body> </div><div class=\"line\"></html></div></pre></td></tr></table></figure></p>\n<h1 id=\"返回使用Json格式\"><a href=\"#返回使用Json格式\" class=\"headerlink\" title=\"返回使用Json格式\"></a>返回使用Json格式</h1><p>只需在@ExceptionHandler之后加入@ResponseBody,就能让处理函数return的内容转换为JSON格式</p>\n<h2 id=\"创建一个JSON返回对象,如:\"><a href=\"#创建一个JSON返回对象,如:\" class=\"headerlink\" title=\"创建一个JSON返回对象,如:\"></a>创建一个JSON返回对象,如:</h2><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">public class ErrorDTO implements Serializable {</div><div class=\"line\"></div><div class=\"line\"> private static final long serialVersionUID = <span class=\"number\">1</span>L;</div><div class=\"line\"></div><div class=\"line\"> private final String message;</div><div class=\"line\"> private final String description;</div><div class=\"line\"></div><div class=\"line\"> private List<FieldErrorDTO> fieldErrors;</div><div class=\"line\"></div><div class=\"line\"> //getter和setter省略</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"可以为指定的Exception添加异常处理\"><a href=\"#可以为指定的Exception添加异常处理\" class=\"headerlink\" title=\"可以为指定的Exception添加异常处理\"></a>可以为指定的Exception添加异常处理</h2><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">@ExceptionHandler(ConcurrencyFailureException.class)</div><div class=\"line\"> @ResponseStatus(HttpStatus.CONFLICT)</div><div class=\"line\"> @ResponseBody</div><div class=\"line\"> public ErrorDTO processConcurencyError(ConcurrencyFailureException ex) {</div><div class=\"line\"> return new ErrorDTO(ErrorConstants.ERR_CONCURRENCY_FAILURE);</div><div class=\"line\"> }</div></pre></td></tr></table></figure>\n<p>ErrorConstants.ERR_CONCURRENCY_FAILURE 是定义的一个异常信息。</p>\n"},{"title":"Spring Cloud服务网关","url":"https://yangzhiw.github.io/2016/08/25/Spring-Cloud服务网关/","content":"<p>常用的微服务架构<br><img src=\"/2016/08/25/Spring-Cloud服务网关/zuul.jpg\" alt=\"微服务架构\" title=\"微服务架构\"></p>\n<blockquote>\n<p>种种架构的不足就是缺少权限控制, 现在我们需要增加的就是服务网关了,<br>服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、<br>均衡负载功能之外,它还具备了权限控制等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色,<br>为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,<br>使得服务集群主体能够具备更高的可复用性和可测试性。</p>\n</blockquote>\n<p>下面我们通过实例例子来使用一下Zuul来作为服务的路有功能</p>\n<h1 id=\"准备工作\"><a href=\"#准备工作\" class=\"headerlink\" title=\"准备工作\"></a>准备工作</h1><p>在使用Zuul之前,我们先构建一个服务注册中心、以及两个简单的服务,比如:我构建了一个simple-service,<br>一个simple-service1。然后启动eureka-server和这两个服务。<br>通过访问eureka-server,我们可以看到simple-service和simple-service1已经注册到了服务中心。</p>\n<h1 id=\"开始使用Zuul\"><a href=\"#开始使用Zuul\" class=\"headerlink\" title=\"开始使用Zuul\"></a>开始使用Zuul</h1><p>引入依赖spring-cloud-starter-zuul、spring-cloud-starter-eureka,如果不是通过指定serviceId的方式,eureka依赖不需要,<br>但是为了对服务集群细节的透明性,还是用serviceId来避免直接引用url的方式吧。</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div></pre></td><td class=\"code\"><pre><div class=\"line\"><dependency<span class=\"string\">> </span></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-starter-zuul</artifactId></div><div class=\"line\"></dependency></div><div class=\"line\"></div><div class=\"line\"><dependency> </div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-starter-eureka</artifactId></div><div class=\"line\"></dependency> </div><div class=\"line\"></div><div class=\"line\"><dependencyManagement></div><div class=\"line\">\t\t<dependencies></div><div class=\"line\">\t\t\t<dependency></div><div class=\"line\">\t\t\t\t<groupId>org.springframework.cloud</groupId></div><div class=\"line\">\t\t\t\t<artifactId>spring-cloud-dependencies</artifactId></div><div class=\"line\">\t\t\t\t<version>Brixton.RELEASE</version></div><div class=\"line\">\t\t\t\t<type>pom</type></div><div class=\"line\">\t\t\t\t<scope>import</scope></div><div class=\"line\">\t\t\t</dependency></div><div class=\"line\">\t\t</dependencies></div><div class=\"line\"></dependencyManagement></div></pre></td></tr></table></figure>\n<p>应用主类使用@EnableZuulProxy注解开启Zuul<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">@EnableZuulProxy</div><div class=\"line\">@SpringCloudApplication</div><div class=\"line\">public class ApiGatewayApplication {</div><div class=\"line\"></div><div class=\"line\">\tpublic static void main(String[] args) {</div><div class=\"line\">\t\tSpringApplication.run(ApiGatewayApplication.class, args);</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>@SpringCloudApplication注解,通过源码我们看到,<br>它整合了@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker</p>\n<p>application.properties中配置Zuul应用的基础信息,如:应用名、服务端口等。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">spring.application.name=api-gateway </div><div class=\"line\">server.port=<span class=\"number\">5555</span> </div><div class=\"line\">eureka.client.serviceUrl.defaultZone=http://localhost:<span class=\"number\">11111</span>/eureka/</div></pre></td></tr></table></figure></p>\n<p>在Zuul中提供了两种映射方式:</p>\n<h2 id=\"通过url直接映射,我们可以如下配置:\"><a href=\"#通过url直接映射,我们可以如下配置:\" class=\"headerlink\" title=\"通过url直接映射,我们可以如下配置:\"></a>通过url直接映射,我们可以如下配置:</h2><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\"># routes to url</span></div><div class=\"line\">zuul.routes.api-a-url.path=/api-a-url/** </div><div class=\"line\">zuul.routes.api-a-url.url=http://localhost:<span class=\"number\">2222</span>/</div></pre></td></tr></table></figure>\n<p>该配置,定义了,所有到Zuul的中规则为:/api-a-url/**的访问都映射到<a href=\"http://localhost:2222/上,\" target=\"_blank\" rel=\"external\">http://localhost:2222/上,</a><br>也就是说当我们访问<a href=\"http://localhost:5555/api-a-url/add?a=1&b=2的时候,Zuul会将该请求路由到:\" target=\"_blank\" rel=\"external\">http://localhost:5555/api-a-url/add?a=1&b=2的时候,Zuul会将该请求路由到:</a><br><a href=\"http://localhost:2222/add?a=1&b=2上。\" target=\"_blank\" rel=\"external\">http://localhost:2222/add?a=1&b=2上。</a></p>\n<h2 id=\"通过serviceId的映射\"><a href=\"#通过serviceId的映射\" class=\"headerlink\" title=\"通过serviceId的映射\"></a>通过serviceId的映射</h2><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">zuul.routes.api-a.path=/api-a/** </div><div class=\"line\">zuul.routes.api-a.serviceId=service-A</div><div class=\"line\"></div><div class=\"line\">zuul.routes.api-b.path=/api-b/** </div><div class=\"line\">zuul.routes.api-b.serviceId=service-B</div></pre></td></tr></table></figure>\n<p>通过浏览器就可以访问了。如<a href=\"http://localhost:5555/api-b\" target=\"_blank\" rel=\"external\">http://localhost:5555/api-b</a></p>\n<h1 id=\"服务过滤\"><a href=\"#服务过滤\" class=\"headerlink\" title=\"服务过滤\"></a>服务过滤</h1><p>在完成了服务路由之后,我们对外开放服务还需要一些安全措施来保护客户端只能访问它应该访问到的资源。<br>所以我们需要利用Zuul的过滤器来实现我们对外服务的安全控制。<br>在服务网关中定义过滤器只需要继承ZuulFilter抽象类实现其定义的四个抽象函数就可对请求进行拦截与过滤。</p>\n<p>自定义过滤器的实现,需要继承ZuulFilter,需要重写实现下面四个方法:<br>filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:<br> pre:可以在请求被路由之前调用<br> routing:在路由请求时候被调用<br> post:在routing和error过滤器之后被调用<br> error:处理请求时发生错误时被调用<br>filterOrder:通过int值来定义过滤器的执行顺序<br>shouldFilter:返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关,默认false,不执行<br>run:过滤器的具体逻辑</p>\n<p>然后在主类中注入该类<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">@Bean</div><div class=\"line\">public FilterTest filterTest() {</div><div class=\"line\">\treturn new FilterTest();</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>最后在浏览器中输入<a href=\"http://localhost:5555/api-b/add?a=1&b=2就不可以访问,\" target=\"_blank\" rel=\"external\">http://localhost:5555/api-b/add?a=1&b=2就不可以访问,</a><br>而<a href=\"http://localhost:5555/api-b/add?a=1&b=2&c=d可以访问了\" target=\"_blank\" rel=\"external\">http://localhost:5555/api-b/add?a=1&b=2&c=d可以访问了</a></p>\n<p>根据之前对filterType生命周期介绍,可以参考下图去理解,并根据自己的需要在不同的生命周期中去实现不同类型的过滤器。<br><img src=\"/2016/08/25/Spring-Cloud服务网关/zuul1.jpg\" alt=\"filterType生命周期\" title=\"filterType生命周期\"></p>\n<p>总结:<br>服务网关的优点:<br>不仅仅实现了路由功能来屏蔽诸多服务细节,更实现了服务级别、均衡负载的路由。<br>实现了接口权限校验与微服务业务逻辑的解耦。通过服务网关中的过滤器,在各生命周期中去校验请求的内容,<br>将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,<br>让服务本身更集中关注业务逻辑的处理。<br>实现了断路器,不会因为具体微服务的故障而导致服务网关的阻塞,依然可以对外服务。</p>\n"},{"title":"Spring Cloud分布式配置","url":"https://yangzhiw.github.io/2016/08/24/Spring-Cloud分布式配置/","content":"<p>Spring Cloud Config为服务端和客户端提供了分布式系统的外部化配置支持。<br>配置服务器为各应用的所有环境提供了一个中心化的外部配置。它实现了对服务端和客户端对Spring Environment<br>和PropertySource抽象的映射,所以它除了适用于Spring构建的应用程序,也可以在任何其他语言运行的应用程序中使用。<br>作为一个应用可以通过部署管道来进行测试或者投入生产,我们可以分别为这些环境创建配置,<br>并且在需要迁移环境的时候获取对应环境的配置来运行。<br>配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的<br>管理和访问配置内容。当然他也提供本地化文件系统的存储方式,下面从这两方面介绍如何使用分布式配置来存储微服务<br>应用多环境的配置内容。</p>\n<h1 id=\"构建Config-Server\"><a href=\"#构建Config-Server\" class=\"headerlink\" title=\"构建Config Server\"></a>构建Config Server</h1><p>场景Spring Boot初始项目,然后在pom.xml中添加如下依赖。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\"><dependency<span class=\"string\">></span></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-config-server</artifactId></div><div class=\"line\"> </dependency></div><div class=\"line\"> <dependencyManagement></div><div class=\"line\"> \t<dependencies></div><div class=\"line\"> \t<dependency></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-dependencies</artifactId></div><div class=\"line\"> <version>Brixton.RELEASE</version></div><div class=\"line\"> <type>pom</type></div><div class=\"line\"> <scope>import</scope></div><div class=\"line\"> \t</dependency></div><div class=\"line\"> \t \t</dependencies></div><div class=\"line\"> </dependencyManagement></div></pre></td></tr></table></figure></p>\n<p>在Spring Boot主类中添加@EnableConfigServer注解,开启config-server功能<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">@EnableConfigServer</div><div class=\"line\">@SpringBootApplication</div><div class=\"line\">public class Application {</div><div class=\"line\"></div><div class=\"line\"> public static void main(String[] args) {</div><div class=\"line\"> new SpringApplicationBuilder(Application.class).web(<span class=\"literal\">true</span>).run(args);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>在application.properties中配置服务信息以及git信息,如:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">spring.application.name=config-server</div><div class=\"line\">server.port=<span class=\"number\">7001</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\"># git管理配置</span></div><div class=\"line\">spring.cloud.config.server.git.uri=https://github.com/yangzhiw/Simple-Spring-Cloud</div><div class=\"line\">spring.cloud.config.server.git.searchPaths=config-repo</div><div class=\"line\">spring.cloud.config.server.git.username=username</div><div class=\"line\">spring.cloud.config.server.git.password=password</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\"># 开启本地配置</span></div><div class=\"line\"><span class=\"comment\"># spring.profiles.active=native</span></div></pre></td></tr></table></figure></p>\n<p>spring.cloud.config.server.git.uri:配置git仓库位置<br>spring.cloud.config.server.git.searchPaths:配置仓库路径下的相对搜索位置,可以配置多个<br>spring.cloud.config.server.git.username:访问git仓库的用户名<br>spring.cloud.config.server.git.password:访问git仓库的用户密码</p>\n<p>Spring Cloud Config也提供本地存储配置的方式。我们只需要设置属性spring.profiles.active=native,<br>Config Server会默认从应用的src/main/resource目录下检索配置文件。也可以通过<br>spring.cloud.config.server.native.searchLocations=file:D:/properties/属性来指定配置文件的位置。<br>虽然Spring Cloud Config提供了这样的功能,但是为了支持更好的管理内容和版本控制的功能,<br>还是推荐使用git的方式</p>\n<h1 id=\"服务端验证\"><a href=\"#服务端验证\" class=\"headerlink\" title=\"服务端验证\"></a>服务端验证</h1><p>在项目中创建一个config-repo文件夹,配置了四个配置文件<br>配置文件分别为:<br>juzi.properties<br>juzi-dev.properties<br>juzi-test.properties<br>juzi-prod.properties<br>可以在四个配置文件中设置属性</p>\n<h2 id=\"URL与配置文件的映射关系如下:\"><a href=\"#URL与配置文件的映射关系如下:\" class=\"headerlink\" title=\"URL与配置文件的映射关系如下:\"></a>URL与配置文件的映射关系如下:</h2><p>/{application}/{profile}[/{label}]<br>/{application}-{profile}.yml<br>/{label}/{application}-{profile}.yml<br>/{application}-{profile}.properties<br>/{label}/{application}-{profile}.properties<br>上面的url会映射{application}-{profile}.properties对应的配置文件,{label}对应git上不同的分支,默认为master。<br>然后我们就可访问我们的配置文件了。如:<a href=\"http://localhost:7001/juzi/prod/\" target=\"_blank\" rel=\"external\">http://localhost:7001/juzi/prod/</a><br>这便是访问生成环境的配置文件。</p>\n<h1 id=\"服务端配置映射\"><a href=\"#服务端配置映射\" class=\"headerlink\" title=\"服务端配置映射\"></a>服务端配置映射</h1><p>在完成并验证了配置服务中心之后,下面看看我们如何在微服务应用中获取配置信息。</p>\n<p>创建一个Spring Boot应用,在pom.xml中引入spring-cloud-starter-config依赖,完整依赖关系如下:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div></pre></td><td class=\"code\"><pre><div class=\"line\"> </div><div class=\"line\"><dependency<span class=\"string\">></span></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-starter-config</artifactId></div><div class=\"line\"></dependency></div><div class=\"line\"></div><div class=\"line\"><dependencyManagement></div><div class=\"line\"> <dependencies></div><div class=\"line\"> <dependency></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-dependencies</artifactId></div><div class=\"line\"> <version>Brixton.RELEASE</version></div><div class=\"line\"> <type>pom</type></div><div class=\"line\"> <scope>import</scope></div><div class=\"line\"> </dependency></div><div class=\"line\"> </dependencies></div><div class=\"line\"></dependencyManagement></div></pre></td></tr></table></figure></p>\n<p>创建bootstrap.properties配置,来指定config server,例如:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">spring.application.name=didispace </div><div class=\"line\">spring.cloud.config.profile=dev </div><div class=\"line\">spring.cloud.config.label=master </div><div class=\"line\">spring.cloud.config.uri=http://localhost:<span class=\"number\">7001</span>/</div><div class=\"line\"></div><div class=\"line\">server.port=<span class=\"number\">7002</span></div></pre></td></tr></table></figure></p>\n<p>这里需要格外注意:上面这些属性必须配置在bootstrap.properties中,config部分内容才能被正确加载。<br>因为config的相关配置会先于application.properties,<br>而bootstrap.properties的加载也是先于application.properties。</p>\n<p> 这里需要格外注意:上面这些属性必须配置在bootstrap.properties中,config部分内容才能被正确加载。<br> 因为config的相关配置会先于application.properties,<br> 而bootstrap.properties的加载也是先于application.properties。<br> <figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\"> @RefreshScope</div><div class=\"line\">@RestController</div><div class=\"line\">class TestController {</div><div class=\"line\"></div><div class=\"line\"> @Value(<span class=\"string\">\"${from}\"</span>)</div><div class=\"line\"> private String from;</div><div class=\"line\"></div><div class=\"line\"> @RequestMapping(<span class=\"string\">\"/from\"</span>)</div><div class=\"line\"> public String from() {</div><div class=\"line\"></div><div class=\"line\"> return this.from;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>通过@Value(“${from}”)绑定配置服务中配置的from属性。</p>\n<p>启动该应用,并访问:<a href=\"http://localhost:7002/from\" target=\"_blank\" rel=\"external\">http://localhost:7002/from</a> ,我们就可以根据配置内容输出对应环境的from内容了。</p>\n"},{"title":"Spring Cloud路断器","url":"https://yangzhiw.github.io/2016/08/24/Spring-Cloud路断器/","content":"<h1 id=\"什么是断路器\"><a href=\"#什么是断路器\" class=\"headerlink\" title=\"什么是断路器\"></a>什么是断路器</h1><p>断路器模式源于Martin Fowler的Circuit Breaker一文。“断路器”本身是一种开关装置,用于在电路上保护线路过载,<br>当线路中有电器发生短路时,“断路器”能够及时的切断故障电路,防止发生过载、发热、甚至起火等严重后果。</p>\n<p>在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,<br>通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。<br>这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延.</p>\n<h1 id=\"Netflix-Hystrix\"><a href=\"#Netflix-Hystrix\" class=\"headerlink\" title=\"Netflix Hystrix\"></a>Netflix Hystrix</h1><p>在Spring Cloud中使用了Hystrix 来实现断路器的功能。Hystrix是Netflix开源的微服务框架套件之一,<br>该框架目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。<br>Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。</p>\n<p>下面我们来看看如何使用Hystrix。</p>\n<h2 id=\"准备工作\"><a href=\"#准备工作\" class=\"headerlink\" title=\"准备工作\"></a>准备工作</h2><p>启动spring-could,spring-cloud-provide,eureka-ribbon项目</p>\n<p>pom.xml中引入依赖hystrix依赖<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><dependency<span class=\"string\">> </span></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-starter-hystrix</artifactId></div><div class=\"line\"></dependency></div></pre></td></tr></table></figure></p>\n<p>在eureka-ribbon的主类RibbonApplication中使用@EnableCircuitBreaker注解开启断路器功能<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">@SpringBootApplication</div><div class=\"line\">@EnableDiscoveryClient</div><div class=\"line\">@EnableCircuitBreaker</div><div class=\"line\">public class EurekaRibbonApplication {</div></pre></td></tr></table></figure></p>\n<p>新增也service类<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">@Service</div><div class=\"line\">public class SimpleService {</div><div class=\"line\"> @Autowired</div><div class=\"line\"> RestTemplate restTemplate;</div><div class=\"line\"></div><div class=\"line\"> @HystrixCommand(fallbackMethod = <span class=\"string\">\"addServiceFallback\"</span>)</div><div class=\"line\"> public String addService() {</div><div class=\"line\"> return restTemplate.getForEntity(<span class=\"string\">\"http://COMPUTE-SERVICE/add?a=10&b=20\"</span>, String.class).getBody();</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> public String addServiceFallback() {</div><div class=\"line\"> return <span class=\"string\">\"error\"</span>;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>改变之前Controller中的方法使其掉用Service中的addService即可,没开服务可以发现浏览器中返回了error错误了。<br>完成</p>\n"},{"title":"Spring Cloud服务消费者","url":"https://yangzhiw.github.io/2016/08/24/Spring-Cloud服务消费者/","content":"<h1 id=\"Ribbon\"><a href=\"#Ribbon\" class=\"headerlink\" title=\"Ribbon\"></a>Ribbon</h1><p>Ribbon是一个基于HTTP和TCP的客户端负载均衡器。<br>Ribbon可以在通过客户端中配置的ribbonServerList服务端列表去轮询访问以达到均衡负载的作用。</p>\n<p>1.启动之前的spring-could<br>2.启动服务提供方spring-cloud-provide</p>\n<p>修改spring-cloud-provide中的server-port为2223,再启动一个服务提供方:service</p>\n<h1 id=\"使用Ribbon实现客户端负载均衡的消费者\"><a href=\"#使用Ribbon实现客户端负载均衡的消费者\" class=\"headerlink\" title=\"使用Ribbon实现客户端负载均衡的消费者\"></a>使用Ribbon实现客户端负载均衡的消费者</h1><p>在pom.xml中添加<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\"><dependency<span class=\"string\">></span></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-starter-ribbon</artifactId></div><div class=\"line\"> </dependency></div><div class=\"line\"> <dependency></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-starter-eureka</artifactId></div><div class=\"line\"> </dependency></div><div class=\"line\"> <dependencyManagement> </div><div class=\"line\"> <dependencies></div><div class=\"line\"> <dependency></div><div class=\"line\">\t <groupId>org.springframework.cloud</groupId></div><div class=\"line\">\t <artifactId>spring-cloud-dependencies</artifactId></div><div class=\"line\">\t <version>Brixton.RELEASE</version></div><div class=\"line\">\t <type>pom</type></div><div class=\"line\">\t <scope>import</scope></div><div class=\"line\"> \t</dependency></div><div class=\"line\"> </dependencies></div><div class=\"line\"></dependencyManagement></div></pre></td></tr></table></figure></p>\n<p>在应用主类中,通过@EnableDiscoveryClient注解来添加发现服务能力。<br>创建RestTemplate实例,并通过@LoadBalanced注解开启均衡负载能力。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\">@SpringBootApplication</div><div class=\"line\">@EnableDiscoveryClient</div><div class=\"line\">public class RibbonApplication {</div><div class=\"line\"></div><div class=\"line\"> @Bean</div><div class=\"line\"> @LoadBalanced</div><div class=\"line\"> RestTemplate restTemplate() {</div><div class=\"line\"> return new RestTemplate();</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> public static void main(String[] args) {</div><div class=\"line\"> SpringApplication.run(RibbonApplication.class, args);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>创建ConsumerController来消费COMPUTE-SERVICE的add服务。<br>通过直接RestTemplate来调用服务,计算10 + 20的值。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\">@RestController</div><div class=\"line\">public class ConsumerController {</div><div class=\"line\"></div><div class=\"line\"> @Autowired</div><div class=\"line\"> RestTemplate restTemplate;</div><div class=\"line\"></div><div class=\"line\"> @RequestMapping(value = <span class=\"string\">\"/add\"</span>, method = RequestMethod.GET)</div><div class=\"line\"> public String add() {</div><div class=\"line\"> return restTemplate.getForEntity(<span class=\"string\">\"http://COMPUTE-SERVICE/add?a=10&b=20\"</span>, String.class).getBody();</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>application.properties中配置eureka服务注册中心<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">spring.application.name=ribbon-consumer </div><div class=\"line\">server.port=<span class=\"number\">3333</span></div><div class=\"line\"></div><div class=\"line\">eureka.client.serviceUrl.defaultZone=http://localhost:<span class=\"number\">1111</span>/eureka/</div></pre></td></tr></table></figure></p>\n<p>然后启动该项目,在浏览器中输入<a href=\"http://localhost:3333/add\" target=\"_blank\" rel=\"external\">http://localhost:3333/add</a><br>在2222和2223的端口总能看到有其中一个控制台有日志打出,关闭一个,还能继续运行<br>即通过ribbon实现了负载均衡了。</p>\n"},{"title":"Spring Cloud服务注册与发现","url":"https://yangzhiw.github.io/2016/08/23/Spring-Cloud服务注册与发现/","content":"<h1 id=\"Spring-Cloud简介\"><a href=\"#Spring-Cloud简介\" class=\"headerlink\" title=\"Spring Cloud简介\"></a>Spring Cloud简介</h1><p>Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、<br>服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简<br>Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config、<br>Spring Cloud Netflix、Spring Cloud CloudFoundry、Spring Cloud AWS、Spring Cloud Security、Spring Cloud Commons、<br>pring Cloud Zookeeper、Spring Cloud CLI等项目。</p>\n<h1 id=\"微服务架构\"><a href=\"#微服务架构\" class=\"headerlink\" title=\"微服务架构\"></a>微服务架构</h1><p>“微服务架构”在这几年非常的火热,以至于关于微服务架构相关的产品社区也变得越来越活跃(比如:netflix、dubbo),<br>Spring Cloud也因Spring社区的强大知名度和影响力也被广大架构师与开发者备受关注。</p>\n<h1 id=\"服务注册与发现\"><a href=\"#服务注册与发现\" class=\"headerlink\" title=\"服务注册与发现\"></a>服务注册与发现</h1><p>这里用到Spring Cloud Netflix,该项目是Spring Cloud的子项目之一,主要内容是对Netflix公司一系列开源产品的包装,<br> 它为Spring Boot应用提供了自配置的Netflix OSS整合。通过一些简单的注解,开发者就可以快速的在应用中配置一下常用<br> 模块并构建庞大的分布式系统。它主要提供的模块包括:服务发现(Eureka),断路器(Hystrix),智能路由(Zuul),<br> 客户端负载均衡(Ribbon)等。<br>所以,我们这里的核心内容就是服务发现模块:Eureka。下面我们动手来做一些尝试。</p>\n<h2 id=\"创建“服务注册中心”\"><a href=\"#创建“服务注册中心”\" class=\"headerlink\" title=\"创建“服务注册中心”\"></a>创建“服务注册中心”</h2><p>创建一个基础的Spring Boot工程,并在pom.xml中引入需要的依赖内容:</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div></pre></td><td class=\"code\"><pre><div class=\"line\">\t<parent<span class=\"string\">></span></div><div class=\"line\">\t\t<groupId>org.springframework.boot</groupId></div><div class=\"line\">\t\t<artifactId>spring-boot-starter-parent</artifactId></div><div class=\"line\">\t\t<version>1.4.0.RELEASE</version></div><div class=\"line\">\t\t<relativePath/> <!-- lookup parent from repository --></div><div class=\"line\">\t</parent></div><div class=\"line\"></div><div class=\"line\">\t<dependencies> </div><div class=\"line\">\t <dependency></div><div class=\"line\">\t <groupId>org.springframework.boot</groupId></div><div class=\"line\">\t <artifactId>spring-boot-starter-test</artifactId></div><div class=\"line\">\t <scope>test</scope></div><div class=\"line\">\t </dependency></div><div class=\"line\"></div><div class=\"line\">\t <dependency></div><div class=\"line\">\t <groupId>org.springframework.cloud</groupId></div><div class=\"line\">\t <artifactId>spring-cloud-starter-eureka-server</artifactId></div><div class=\"line\">\t </dependency></div><div class=\"line\">\t</dependencies></div><div class=\"line\">\t<dependencyManagement> </div><div class=\"line\">\t <dependencies></div><div class=\"line\">\t <dependency></div><div class=\"line\">\t <groupId>org.springframework.cloud</groupId></div><div class=\"line\">\t <artifactId>spring-cloud-dependencies</artifactId></div><div class=\"line\">\t <version>Brixton.RELEASE</version></div><div class=\"line\">\t <type>pom</type></div><div class=\"line\">\t <scope>import</scope></div><div class=\"line\">\t </dependency></div><div class=\"line\"> </dependencies></div><div class=\"line\"></dependencyManagement></div></pre></td></tr></table></figure>\n<p>通过@EnableEurekaServer注解启动一个服务注册中心提供给其他应用进行对话。<br>这一步非常的简单,只需要在一个普通的Spring Boot应用中添加这个注解就能开启此功能,比如下面的例子:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">@SpringBootApplication</div><div class=\"line\">@EnableEurekaServer</div><div class=\"line\">public class SpringCloudApplication {</div><div class=\"line\"></div><div class=\"line\">\tpublic static void main(String[] args) {</div><div class=\"line\">\t\tSpringApplication.run(SpringCloudApplication.class, args);</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,<br>所以我们需要禁用它的客户端注册行为,只需要在application.properties中问增加如下配置:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">server.port=<span class=\"number\">11111</span></div><div class=\"line\"></div><div class=\"line\">eureka.client.register-with-eureka=<span class=\"literal\">false</span> </div><div class=\"line\">eureka.client.fetch-registry=<span class=\"literal\">false</span> </div><div class=\"line\">eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/</div></pre></td></tr></table></figure></p>\n<p>启动项目,在浏览器输入网址:<a href=\"http://localhost:11111\" target=\"_blank\" rel=\"external\">http://localhost:11111</a><br>可以看到注册中心已经启动了</p>\n<h1 id=\"创建服务提供方\"><a href=\"#创建服务提供方\" class=\"headerlink\" title=\"创建服务提供方\"></a>创建服务提供方</h1><p>现在 提供计算功能的微服务模块,我们实现一个RESTful API,通过传入两个参数a和b,最后返回a + b的结果。</p>\n<p>首先,创建一个基本的Spring Boot应用,在pom.xml中,加入如下配置:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div></pre></td><td class=\"code\"><pre><div class=\"line\"><parent<span class=\"string\">></span></div><div class=\"line\">\t\t<groupId>org.springframework.boot</groupId></div><div class=\"line\">\t\t<artifactId>spring-boot-starter-parent</artifactId></div><div class=\"line\">\t\t<version>1.4.0.RELEASE</version></div><div class=\"line\">\t\t<relativePath/> <!-- lookup parent from repository --></div><div class=\"line\"></parent></div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"><dependencies> </div><div class=\"line\"> <dependency></div><div class=\"line\"> <groupId>org.springframework.boot</groupId></div><div class=\"line\"> <artifactId>spring-boot-starter-test</artifactId></div><div class=\"line\"> <scope>test</scope></div><div class=\"line\"> </dependency></div><div class=\"line\"></div><div class=\"line\"> <dependency></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-starter-eureka</artifactId></div><div class=\"line\"> </dependency></div><div class=\"line\"></dependencies></div><div class=\"line\"></div><div class=\"line\"><dependencyManagement> </div><div class=\"line\"> <dependencies></div><div class=\"line\"> <dependency></div><div class=\"line\"> <groupId>org.springframework.cloud</groupId></div><div class=\"line\"> <artifactId>spring-cloud-dependencies</artifactId></div><div class=\"line\"> <version>Brixton.RELEASE</version></div><div class=\"line\"> <type>pom</type></div><div class=\"line\"> <scope>import</scope></div><div class=\"line\"> </dependency></div><div class=\"line\"> </dependencies></div><div class=\"line\"></dependencyManagement></div></pre></td></tr></table></figure></p>\n<p>其次,实现/add请求处理接口,通过DiscoveryClient对象,在日志中打印出服务实例的相关内容。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div></pre></td><td class=\"code\"><pre><div class=\"line\">@RestController</div><div class=\"line\">public class ComputeController {</div><div class=\"line\"></div><div class=\"line\"> private final Logger logger = LoggerFactory.getLogger(getClass());</div><div class=\"line\"></div><div class=\"line\"> @Autowired</div><div class=\"line\"> private DiscoveryClient client;</div><div class=\"line\"></div><div class=\"line\"> @RequestMapping(value = <span class=\"string\">\"/add\"</span> ,method = RequestMethod.GET)</div><div class=\"line\"> public Integer add(@RequestParam Integer a, @RequestParam Integer b) {</div><div class=\"line\"> ServiceInstance instance = client.getLocalServiceInstance();</div><div class=\"line\"> Integer r = a + b;</div><div class=\"line\"> logger.info(<span class=\"string\">\"/add, host:\"</span> + instance.getHost() + <span class=\"string\">\", service_id:\"</span> + instance.getServiceId() + <span class=\"string\">\", result:\"</span> + r);</div><div class=\"line\"> return r;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>最后在主类中通过加上@EnableDiscoveryClient注解,<br>该注解能激活Eureka中的DiscoveryClient实现,才能实现Controller中对服务信息的输出。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">@SpringBootApplication</div><div class=\"line\">@EnableDiscoveryClient</div><div class=\"line\">public class SpringCloudProvideApplication {</div><div class=\"line\"></div><div class=\"line\">\tpublic static void main(String[] args) {</div><div class=\"line\">\t\tSpringApplication.run(SpringCloudProvideApplication.class, args);</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>application.properties的配置<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">spring.application.name=compute-service</div><div class=\"line\"></div><div class=\"line\">server.port=<span class=\"number\">2222</span></div><div class=\"line\"></div><div class=\"line\">eureka.client.serviceUrl.defaultZone=http://localhost:<span class=\"number\">11111</span>/eureka/</div></pre></td></tr></table></figure></p>\n<p>通过spring.application.name属性,我们可以指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问。</p>\n<p>eureka.client.serviceUrl.defaultZone属性对应服务注册中心的配置内容,指定服务注册中心的位置。</p>\n<p>为了在本机上测试区分服务提供方和服务注册中心,使用server.port属性设置不同的端口。<br>启动该工程后,再次访问:<a href=\"http://localhost:11111/\" target=\"_blank\" rel=\"external\">http://localhost:11111/</a></p>\n"},{"title":"Kafka入门","url":"https://yangzhiw.github.io/2016/08/23/Kafka入门/","content":"<h1 id=\"基础知识\"><a href=\"#基础知识\" class=\"headerlink\" title=\"基础知识\"></a>基础知识</h1><h2 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h2><p>Kafka是一个分布式的、可分区的、可复制的消息系统。它提供了普通消息系统的功能,但具有自己独特的设计。<br>首先让我们看几个基本的消息系统术语:<br>Kafka将消息以topic为单位进行归纳。<br>将向Kafka topic发布消息的程序成为producers.<br>将预订topics并消费消息的程序成为consumer.<br>Kafka以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个broker.<br></p>\n<h2 id=\"分布式\"><a href=\"#分布式\" class=\"headerlink\" title=\"分布式\"></a>分布式</h2><p>每个分区在Kafka集群的若干服务中都有副本,这样这些持有副本的服务可以共同处理数据和请求,副本数量是可以配置的。副本使Kafka具备了容错能力。<br>每个分区都由一个服务器作为“leader”,零或若干服务器作为“followers”,leader负责处理消息的读和写,followers则去复制leader.如果leader down了,<br>followers中的一台则会自动成为leader。集群中的每个服务都会同时扮演两个角色:<br>作为它所持有的一部分分区的leader,同时作为其他分区的followers,这样集群就会据有较好的负载均衡。</p>\n<h2 id=\"Producers\"><a href=\"#Producers\" class=\"headerlink\" title=\"Producers\"></a>Producers</h2><p>Producer将消息发布到它指定的topic中,并负责决定发布到哪个分区。通常简单的由负载均衡机制随机选择分区,但也可以通过特定的分区函数选择分区。<br>使用的更多的是第二种。</p>\n<h2 id=\"Consumers\"><a href=\"#Consumers\" class=\"headerlink\" title=\"Consumers\"></a>Consumers</h2><p>发布消息通常有两种模式:队列模式(queuing)和发布-订阅模式(publish-subscribe)。队列模式中,consumers可以同时从服务端读取<br>消息,每个消息只被其中一个consumer读到;发布-订阅模式中消息被广播到所有的consumer中。Consumers可以加入一个consumer<br>组,共同竞争一个topic,topic中的消息将被分发到组中的一个成员中。同一组中的consumer可以在不同的程序中,也可以在不同的<br>机器上。如果所有的consumer都在一个组中,这就成为了传统的队列模式,在各consumer中实现负载均衡。如果所有的consumer<br>不在不同的组中,这就成为了发布-订阅模式,所有的消息都被分发到所有的consumer中。更常见的是,每个topic都有若干数量<br>的consumer组,每个组都是一个逻辑上的“订阅者”,为了容错和更好的稳定性,每个组由若干consumer组成。这其实就是一个<br>发布-订阅模式,只不过订阅者是个组而不是单个consumer。<br><br>由两个机器组成的集群拥有4个分区 (P0-P3) 2个consumer组. A组有两个consumerB组有4个<br>相比传统的消息系统,Kafka可以很好的保证有序性。<br>传统的队列在服务器上保存有序的消息,如果多个consumers同时从这个服务器消费消息,服务器就会以消息存储的顺序向<br>consumer分发消息。虽然服务器按顺序发布消息,但是消息是被异步的分发到各consumer上,所以当消息到达时可能已经失去了<br>原来的顺序,这意味着并发消费将导致顺序错乱。为了避免故障,这样的消息系统通常使用“专用consumer”的概念,其实就是<br>只允许一个消费者消费消息,当然这就意味着失去了并发性。<br>在这方面Kafka做的更好,通过分区的概念,Kafka可以在多个consumer组并发的情况下提供较好的有序性和负载均衡。<br>将每个分区分只分发给一个consumer组,这样一个分区就只被这个组的一个consumer消费,就可以顺序的消费这个分区的消息。<br>为有多个分区,依然可以在多个consumer组之间进行负载均衡。注意consumer组的数量不能多于分区的数量,也就是有多少<br>分区就允许多少并发消费。<br>Kafka只能保证一个分区之内消息的有序性,在不同的分区之间是不可以的,这已经可以满足大部分应用的需求。<br>如果需要topic中所有消息的有序性,那就只能让这个topic只有一个分区,当然也就只有一个consumer组消费它。</p>\n<h1 id=\"环境搭建\"><a href=\"#环境搭建\" class=\"headerlink\" title=\"环境搭建\"></a>环境搭建</h1><h2 id=\"下载并解压\"><a href=\"#下载并解压\" class=\"headerlink\" title=\"下载并解压\"></a>下载并解压</h2><p>从<a href=\"http://kafka.apache.org/downloads.html\" target=\"_blank\" rel=\"external\">官网</a>选择下载最新的二进制文件<br>解压<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">tar -vxzf kafka_2<span class=\"number\">.11</span><span class=\"bullet\">-0.10</span><span class=\"number\">.0</span><span class=\"number\">.1</span>.tgz</div><div class=\"line\">cd kafka_2<span class=\"number\">.11</span><span class=\"bullet\">-0.10</span><span class=\"number\">.0</span><span class=\"number\">.1</span></div></pre></td></tr></table></figure></p>\n<h2 id=\"启动\"><a href=\"#启动\" class=\"headerlink\" title=\"启动\"></a>启动</h2><p>1.启动zookeeper<br>2.启动kafka<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-server-start.sh config/server.properties</div></pre></td></tr></table></figure></p>\n<p>3.创建topic<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">使用kafka-topics.sh 创建单分区单副本的topic test:</div><div class=\"line\">bin/kafka-topics.sh --create --zookeeper localhost:<span class=\"number\">2181</span> --replication-factor <span class=\"number\">1</span> --partitions <span class=\"number\">1</span> --topic test</div><div class=\"line\">查看</div><div class=\"line\">bin/kafka-topics.sh --list --zookeeper localhost:<span class=\"number\">2181</span></div><div class=\"line\">test</div></pre></td></tr></table></figure></p>\n<p>4.产生消息<br>使用kafka-console-producer.sh 发送消息:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-console-producer.sh --broker-list localhost:<span class=\"number\">9092</span> --topic test </div><div class=\"line\">Hello world!</div><div class=\"line\">Hello Kafka!</div></pre></td></tr></table></figure></p>\n<p>按Ctrl+C退出<br>5.消费消息<br>使用kafka-console-consumer.sh 接收消息并在终端打印:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-console-consumer.sh --zookeeper localhost:<span class=\"number\">2181</span> --topic test --from-beginning</div><div class=\"line\">Hello world!</div><div class=\"line\">Hello Kafka!</div></pre></td></tr></table></figure></p>\n<a id=\"more\"></a>\n<h1 id=\"集群部署\"><a href=\"#集群部署\" class=\"headerlink\" title=\"集群部署\"></a>集群部署</h1><h2 id=\"单机多broker-集群配置\"><a href=\"#单机多broker-集群配置\" class=\"headerlink\" title=\"单机多broker 集群配置\"></a>单机多broker 集群配置</h2><p>利用单节点部署多个broker。 不同的broker 设置不同的 id,监听端口及日志目录。 例如:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">cp config/server.properties config/server<span class=\"bullet\">-1.</span>properties </div><div class=\"line\">cp config/server.properties config/server<span class=\"bullet\">-2.</span>properties</div></pre></td></tr></table></figure></p>\n<p>编辑配置<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">config/server<span class=\"bullet\">-1.</span>properties:</div><div class=\"line\"> broker.id=<span class=\"number\">1</span></div><div class=\"line\"> port=<span class=\"number\">9093</span></div><div class=\"line\"> log.dir=/tmp/kafka-logs<span class=\"bullet\">-1</span></div><div class=\"line\">config/server<span class=\"bullet\">-2.</span>properties:</div><div class=\"line\"> broker.id=<span class=\"number\">2</span></div><div class=\"line\"> port=<span class=\"number\">9094</span></div><div class=\"line\"> log.dir=/tmp/kafka-logs<span class=\"bullet\">-2</span></div></pre></td></tr></table></figure></p>\n<p>启动Kafka服务:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-server-start.sh config/server<span class=\"bullet\">-1.</span>properties &</div><div class=\"line\">bin/kafka-server-start.sh config/server<span class=\"bullet\">-2.</span>properties &</div></pre></td></tr></table></figure></p>\n<p>创建一个拥有3个副本的topic:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-topics.sh --create --zookeeper localhost:<span class=\"number\">2181</span> --replication-factor <span class=\"number\">3</span> --partitions <span class=\"number\">1</span> --topic my-replicated-topic</div></pre></td></tr></table></figure></p>\n<p>现在我们搭建了一个集群,怎么知道每个节点的信息呢?运行“describe topics”命令就可以了:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-topics.sh --describe --zookeeper localhost:<span class=\"number\">2181</span> --topic my-replicated-topic</div><div class=\"line\"></div><div class=\"line\">显示</div><div class=\"line\"><span class=\"attr\">Topic:</span>my-replicated-topic PartitionCount:<span class=\"number\">1</span> ReplicationFactor:<span class=\"number\">3</span> Configs:</div><div class=\"line\"><span class=\"attr\"> Topic:</span> my-replicated-topic Partition: <span class=\"number\">0</span> Leader: <span class=\"number\">1</span> Replicas: <span class=\"number\">1</span>,<span class=\"number\">2</span>,<span class=\"number\">0</span> Isr: <span class=\"number\">1</span>,<span class=\"number\">2</span>,<span class=\"number\">0</span></div></pre></td></tr></table></figure></p>\n<p>下面解释一下这些输出。第一行是对所有分区的一个描述,然后每个分区都会对应一行,因为我们只有一个分区所以下面就只加了一行。<br>leader:负责处理消息的读和写,leader是从所有节点中随机选择的.<br>replicas:列出了所有的副本节点,不管节点是否在服务中.<br>isr:是正在服务中的节点.<br>在我们的例子中,节点1是作为leader运行。<br>向topic发送消息:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-console-producer.sh --broker-list localhost:<span class=\"number\">9092</span> --topic my-replicated-topic</div></pre></td></tr></table></figure></p>\n<p>my test message 1<br>my test message 2<br>消费者接受这些消息<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">> bin/kafka-console-consumer.sh --zookeeper localhost:<span class=\"number\">2181</span> --from-beginning --topic my-replicated-topic</div></pre></td></tr></table></figure></p>\n<p>测试一下容错能力.Broker 1作为leader运行,现在我们kill掉它:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">> ps | grep server<span class=\"bullet\">-1.</span>properties7564 ttys002 <span class=\"number\">0</span>:<span class=\"number\">15.91</span> /System/Library/Frameworks/JavaVM.framework/Versions/<span class=\"number\">1.6</span>/Home/bin/java...</div><div class=\"line\">> kill <span class=\"bullet\">-9</span> <span class=\"number\">7564</span></div></pre></td></tr></table></figure></p>\n<p>另外一个节点被选做了leader,node 1 不再出现在 in-sync 副本列表中:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">bin/kafka-topics.sh --describe --zookeeper localhost:<span class=\"number\">218192</span> --topic my-replicated-topic</div><div class=\"line\"><span class=\"attr\">Topic:</span>my-replicated-topic PartitionCount:<span class=\"number\">1</span> ReplicationFactor:<span class=\"number\">3</span> Configs:</div><div class=\"line\"><span class=\"attr\"> Topic:</span> my-replicated-topic Partition: <span class=\"number\">0</span> Leader: <span class=\"number\">2</span> Replicas: <span class=\"number\">1</span>,<span class=\"number\">2</span>,<span class=\"number\">0</span> Isr: <span class=\"number\">2</span>,<span class=\"number\">0</span></div></pre></td></tr></table></figure></p>\n<p>虽然最初负责续写消息的leader down掉了,但之前的消息还是可以消费的.</p>\n<h2 id=\"多机多broker-集群配置\"><a href=\"#多机多broker-集群配置\" class=\"headerlink\" title=\"多机多broker 集群配置\"></a>多机多broker 集群配置</h2><p>分别在多个节点按上述方式安装Kafka,配置启动多个Zookeeper 实例。<br>例如: 在10.4.253.22,10.4.253.23,10.4.253.24三台机器部署,Zookeeper配置如下:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">initLimit=<span class=\"number\">5</span></div><div class=\"line\">syncLimit=<span class=\"number\">2</span></div><div class=\"line\">server<span class=\"number\">.1</span>=<span class=\"number\">10.4</span><span class=\"number\">.253</span><span class=\"number\">.22</span>:<span class=\"number\">2888</span>:<span class=\"number\">3888</span></div><div class=\"line\">server<span class=\"number\">.2</span>=<span class=\"number\">10.4</span><span class=\"number\">.253</span><span class=\"number\">.23</span>:<span class=\"number\">2888</span>:<span class=\"number\">3888</span></div><div class=\"line\">server<span class=\"number\">.3</span>=<span class=\"number\">10.4</span><span class=\"number\">.253</span><span class=\"number\">.24</span>:<span class=\"number\">2888</span>:<span class=\"number\">3888</span></div></pre></td></tr></table></figure></p>\n<p>分别配置多个机器上的Kafka服务 设置不同的broke id,zookeeper.connect设置如下:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">zookeeper.connect=<span class=\"number\">10.4</span><span class=\"number\">.253</span><span class=\"number\">.22</span>:<span class=\"number\">2181</span>,<span class=\"number\">10.4</span><span class=\"number\">.253</span><span class=\"number\">.23</span>:<span class=\"number\">2181</span>,<span class=\"number\">10.4</span><span class=\"number\">.253</span><span class=\"number\">.24</span>:<span class=\"number\">2181</span></div></pre></td></tr></table></figure></p>\n<p>启动Zookeeper与Kafka服务,按上文方式产生和消费消息,验证集群功能(本人未验证)。</p>\n"},{"title":"使用Redis做集中式缓存","url":"https://yangzhiw.github.io/2016/08/19/使用Redis做集中式缓存/","content":""},{"title":"Sporing Boot中使用log4j记录日志","url":"https://yangzhiw.github.io/2016/08/19/Boot中使用log4j记录日志/","content":"<h1 id=\"引入log4j依赖\"><a href=\"#引入log4j依赖\" class=\"headerlink\" title=\"引入log4j依赖\"></a>引入log4j依赖</h1><p>在创建Spring Boot工程时,我们引入了spring-boot-starter,其中包含了spring-boot-starter-logging,该依赖内容就是<br>Spring Boot默认的日志框架Logback,所以我们在引入log4j之前,需要先排除该包的依赖,再引入log4j的依赖,就像下面这样:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\"><dependency<span class=\"string\">> </span></div><div class=\"line\"> <groupId>org.springframework.boot</groupId></div><div class=\"line\"> <artifactId>spring-boot-starter</artifactId></div><div class=\"line\"> <exclusions></div><div class=\"line\"> <exclusion> </div><div class=\"line\"> <groupId>org.springframework.boot</groupId></div><div class=\"line\"> <artifactId>spring-boot-starter-logging</artifactId></div><div class=\"line\"> </exclusion></div><div class=\"line\"> </exclusions></div><div class=\"line\"></dependency></div><div class=\"line\"></div><div class=\"line\"><dependency> </div><div class=\"line\"> <groupId>org.springframework.boot</groupId></div><div class=\"line\"> <artifactId>spring-boot-starter-log4j</artifactId></div><div class=\"line\"></dependency></div></pre></td></tr></table></figure></p>\n<h1 id=\"配置log4j-properties\"><a href=\"#配置log4j-properties\" class=\"headerlink\" title=\"配置log4j.properties\"></a>配置log4j.properties</h1><p>在引入了log4j依赖之后,只需要在src/main/resources目录下加入log4j.properties配置文件,就可以开始对应用的日志进行配置使用。</p>\n<h2 id=\"控制台输出\"><a href=\"#控制台输出\" class=\"headerlink\" title=\"控制台输出\"></a>控制台输出</h2><p>通过如下配置,设定root日志的输出级别为INFO,appender为控制台输出stdout</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\"># LOG4J配置</span></div><div class=\"line\">log4j.rootCategory=INFO, stdout</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\"># 控制台输出</span></div><div class=\"line\">\tlog4j.appender.stdout=org.apache.log4j.ConsoleAppender </div><div class=\"line\">\tlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout </div><div class=\"line\">\tlog4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %<span class=\"number\">5</span>p %c{<span class=\"number\">1</span>}:%L - %m%n</div></pre></td></tr></table></figure>\n<h2 id=\"输出到文件\"><a href=\"#输出到文件\" class=\"headerlink\" title=\"输出到文件\"></a>输出到文件</h2><p>在开发环境,我们只是输出到控制台没有问题,但是到了生产或测试环境,或许持久化日志内容,方便追溯问题原因。<br>可以通过添加如下的appender内容,按天输出到不同的文件中去,同时还需要为log4j.rootCategory添加名为file的appender,<br>这样root日志就可以输出到logs/all.log文件中了。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">#</span></div><div class=\"line\">log4j.rootCategory=INFO, stdout, file</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\"># root日志输出</span></div><div class=\"line\">log4j.appender.file=org.apache.log4j.DailyRollingFileAppender </div><div class=\"line\">log4j.appender.file.file=logs/all.log </div><div class=\"line\">log4j.appender.file.DatePattern=<span class=\"string\">'.'</span>yyyy-MM-dd </div><div class=\"line\">log4j.appender.file.layout=org.apache.log4j.PatternLayout </div><div class=\"line\">log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %<span class=\"number\">5</span>p %c{<span class=\"number\">1</span>}:%L - %m%n</div></pre></td></tr></table></figure></p>\n<h2 id=\"分类输出\"><a href=\"#分类输出\" class=\"headerlink\" title=\"分类输出\"></a>分类输出</h2><p>1.可以按不同package进行输出。通过定义输出到logs/my.log的appender,并对com.didispace包下的日志级别设定<br>为DEBUG级别、appender设置为输出到logs/my.log的名为didifile的appender。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\"># com.juzi包下的日志配置</span></div><div class=\"line\">log4j.category.com.juzi=DEBUG, didifile</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\"># com.didispace下的日志输出</span></div><div class=\"line\">log4j.appender.didifile=org.apache.log4j.DailyRollingFileAppender </div><div class=\"line\">log4j.appender.didifile.file=logs/my.log </div><div class=\"line\">log4j.appender.didifile.DatePattern=<span class=\"string\">'.'</span>yyyy-MM-dd </div><div class=\"line\">log4j.appender.didifile.layout=org.apache.log4j.PatternLayout </div><div class=\"line\">log4j.appender.didifile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %<span class=\"number\">5</span>p %c{<span class=\"number\">1</span>}:%L ---- %m%n</div></pre></td></tr></table></figure></p>\n<p>可以对不同级别进行分类,比如对ERROR级别输出到特定的日志文件中,具体配置可以如下。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">og4j.logger.error=errorfile </div><div class=\"line\"><span class=\"comment\"># error日志输出</span></div><div class=\"line\">log4j.appender.errorfile=org.apache.log4j.DailyRollingFileAppender </div><div class=\"line\">log4j.appender.errorfile.file=logs/error.log </div><div class=\"line\">log4j.appender.errorfile.DatePattern=<span class=\"string\">'.'</span>yyyy-MM-dd </div><div class=\"line\">log4j.appender.errorfile.Threshold = ERROR </div><div class=\"line\">log4j.appender.errorfile.layout=org.apache.log4j.PatternLayout </div><div class=\"line\">log4j.appender.errorfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %<span class=\"number\">5</span>p %c{<span class=\"number\">1</span>}:%L - %m%n</div></pre></td></tr></table></figure></p>\n"},{"title":"Spring Boot日志管理","url":"https://yangzhiw.github.io/2016/08/19/Boot日志管理/","content":"<p>Spring Boot在所有内部日志中使用Commons Logging,但是默认配置也提供了对常用日志的支持,<br>如:Java Util Logging,Log4J, Log4J2和Logback。每种Logger都可以通过配置使用控制台或者文件输出日志内容。</p>\n<h1 id=\"日志输出格式\"><a href=\"#日志输出格式\" class=\"headerlink\" title=\"日志输出格式\"></a>日志输出格式</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"number\">2016</span><span class=\"bullet\">-08</span><span class=\"bullet\">-19</span> <span class=\"number\">10</span>:<span class=\"number\">22</span>:<span class=\"number\">04.233</span> INFO <span class=\"number\">7368</span> --- [ main] com.juzi.AsyncTest : Started AsyncTest in <span class=\"number\">10.084</span> seconds (JVM running for <span class=\"number\">12.545</span>)</div></pre></td></tr></table></figure>\n<p>输出内容元素具体如下:</p>\n<p>时间日期 — 精确到毫秒<br>日志级别 — ERROR, WARN, INFO, DEBUG or TRACE<br>进程ID<br>分隔符 — — 标识实际日志的开始<br>线程名 — 方括号括起来(可能会截断控制台输出)<br>Logger名 — 通常使用源代码的类名<br>日志内容</p>\n<h1 id=\"控制台输出\"><a href=\"#控制台输出\" class=\"headerlink\" title=\"控制台输出\"></a>控制台输出</h1><p>在Spring Boot中默认配置了ERROR、WARN和INFO级别的日志输出到控制台。</p>\n<p>我们可以通过两种方式切换至DEBUG级别:<br>1.在运行命令后加入–debug标志,如:$ java -jar myapp.jar –debug<br>2.在application.properties中配置debug=true,该属性置为true的时候,核心Logger(包含嵌入式容器、hibernate、spring)<br>会输出更多内容,但是你自己应用的日志并不会输出为DEBUG级别。</p>\n<h1 id=\"多彩输出\"><a href=\"#多彩输出\" class=\"headerlink\" title=\"多彩输出\"></a>多彩输出</h1><p>如果你的终端支持ANSI,设置彩色输出会让日志更具可读性。通过在application.properties中设置spring.output.ansi.enabled参数来支持。</p>\n<p>1.NEVER:禁用ANSI-colored输出(默认项)<br>2.DETECT:会检查终端是否支持ANSI,是的话就采用彩色输出(推荐项)<br>3.ALWAYS:总是使用ANSI-colored格式输出,若终端不支持的时候,会有很多干扰信息,不推荐使用</p>\n<h1 id=\"文件输出\"><a href=\"#文件输出\" class=\"headerlink\" title=\"文件输出\"></a>文件输出</h1><p>Spring Boot默认配置只会输出到控制台,并不会记录到文件中,但是我们通常生产环境使用时都需要以文件方式记录。</p>\n<p>若要增加文件输出,需要在application.properties中配置logging.file或logging.path属性。</p>\n<p>1.logging.file,设置文件,可以是绝对路径,也可以是相对路径。如:logging.file=my.log<br>2.logging.path,设置目录,会在该目录下创建spring.log文件,并写入日志内容,如:logging.path=/var/log</p>\n<p>日志文件会在10Mb大小的时候被截断,产生新的日志文件,默认级别为:ERROR、WARN、INFO *</p>\n<h1 id=\"级别控制\"><a href=\"#级别控制\" class=\"headerlink\" title=\"级别控制\"></a>级别控制</h1><p>在Spring Boot中只需要在application.properties中进行配置完成日志记录的级别控制。</p>\n<p>配置格式:logging.level.*=LEVEL</p>\n<p>1.logging.level:日志级别控制前缀,*为包名或Logger名<br>2.LEVEL:选项TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF<br>举例:</p>\n<p>logging.level.com.juzi=DEBUG com.juzi包下所有class以DEBUG级别输出<br>logging.level.root=WARN root日志以WARN级别输出</p>\n<h1 id=\"自定义日志配置\"><a href=\"#自定义日志配置\" class=\"headerlink\" title=\"自定义日志配置\"></a>自定义日志配置</h1><p>由于日志服务一般都在ApplicationContext创建前就初始化了,它并不是必须通过Spring的配置文件控制。<br>因此通过系统属性和传统的Spring Boot外部配置文件依然可以很好的支持日志控制和管理。</p>\n<p>根据不同的日志系统,你可以按如下规则组织配置文件名,就能被正确加载:</p>\n<p>1.Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy <a href=\"2016/07/21/logback\">logback日志配置</a><br>2.Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml<br>3.Log4j2:log4j2-spring.xml, log4j2.xml<br>4.JDK (Java Util Logging):logging.properties</p>\n<p>Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用logback-spring.xml,而不是logback.xml)</p>\n<h1 id=\"自定义输出格式\"><a href=\"#自定义输出格式\" class=\"headerlink\" title=\"自定义输出格式\"></a>自定义输出格式</h1><p>在Spring Boot中可以通过在application.properties配置如下参数控制输出格式:</p>\n<p>1.logging.pattern.console:定义输出到控制台的样式(不支持JDK Logger)<br>2.logging.pattern.file:定义输出到文件的样式(不支持JDK Logger)</p>\n"},{"title":"@EnableJpaRepositories配置详解","url":"https://yangzhiw.github.io/2016/08/18/EnableJpaRepositories配置详解/","content":"<h1 id=\"1-简单配置\"><a href=\"#1-简单配置\" class=\"headerlink\" title=\"1,简单配置\"></a>1,简单配置</h1><p>@EnableJpaRepositories(“com.juzi.repository”)<br>或者 @EnableJpaRepositories({“com.juzi.repository”, “com.cshtong.second.repository”})</p>\n<h1 id=\"2-完整的-EnableJpaRepositories注解\"><a href=\"#2-完整的-EnableJpaRepositories注解\" class=\"headerlink\" title=\"2,完整的@EnableJpaRepositories注解\"></a>2,完整的@EnableJpaRepositories注解</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\"> @EnableJpaRepositories(</div><div class=\"line\"> basePackages = {},</div><div class=\"line\"> basePackageClasses = {},</div><div class=\"line\"> includeFilters = {},</div><div class=\"line\"> excludeFilters = {},</div><div class=\"line\"> repositoryImplementationPostfix = <span class=\"string\">\"Impl\"</span>,</div><div class=\"line\"> namedQueriesLocation = <span class=\"string\">\"\"</span>,//META-INF/jpa-named-queries.properties</div><div class=\"line\"> queryLookupStrategy=QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND, //QueryLookupStrategy.Key.x</div><div class=\"line\"> repositoryFactoryBeanClass=JpaRepositoryFactoryBean.class, //class</div><div class=\"line\"> entityManagerFactoryRef=<span class=\"string\">\"entityManagerFactory\"</span>,</div><div class=\"line\"> transactionManagerRef=<span class=\"string\">\"transactionManager\"</span>,</div><div class=\"line\"> considerNestedRepositories=<span class=\"literal\">false</span>, </div><div class=\"line\"> enableDefaultTransactions=<span class=\"literal\">true</span></div><div class=\"line\">)</div></pre></td></tr></table></figure>\n<p>各个配置项的作用<br>1)basePackage<br>用于配置扫描Repositories所在的package及子package。简单配置中的配置则等同于此项配置值,<br>basePackages可以配置为单个字符串,也可以配置为字符串数组形式。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">@EnableJpaRepositories(</div><div class=\"line\"> basePackages = <span class=\"string\">\"com.juzi\"</span>)</div><div class=\"line\">多个包路径</div><div class=\"line\">@EnableJpaRepositories(</div><div class=\"line\"> basePackages = {<span class=\"string\">\"com.juzi.repository\"</span>, <span class=\"string\">\"com.juzi.second.repository\"</span>})</div></pre></td></tr></table></figure></p>\n<p>2)basePackageClasses<br>指定 Repository 类<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">@EnableJpaRepositories(basePackageClasses = BookRepository.class)</div><div class=\"line\"></div><div class=\"line\">@EnableJpaRepositories(</div><div class=\"line\"> basePackageClasses = {ShopRepository.class, OrganizationRepository.class})</div></pre></td></tr></table></figure></p>\n<p>3)includeFilters<br>过滤器,该过滤区采用ComponentScan的过滤器类<br>@EnableJpaRepositories(<br> includeFilters={@ComponentScan.Filter(type=FilterType.ANNOTATION, value=Repository.class)})<br>4)excludeFilters<br>不包含过滤器</p>\n<p>@EnableJpaRepositories(<br> excludeFilters={<br> @ComponentScan.Filter(type=FilterType.ANNOTATION, value=Service.class),<br> @ComponentScan.Filter(type=FilterType.ANNOTATION, value=Controller.class)})</p>\n<p>5)repositoryImplementationPostfix<br>实现类追加的尾部,比如ShopRepository,对应的为ShopRepositoryImpl</p>\n<p>6)namedQueriesLocation<br>named SQL存放的位置,默认为META-INF/jpa-named-queries.properties</p>\n<p>7)queryLookupStrategy<br>构建条件查询的策略,包含三种方式CREATE,USE_DECLARED_QUERY,CREATE_IF_NOT_FOUND</p>\n<p>CREATE:按照接口名称自动构建查询<br>USE_DECLARED_QUERY:用户声明查询<br>CREATE_IF_NOT_FOUND:先搜索用户声明的,不存在则自动构建</p>\n<p>8)repositoryFactoryBeanClass<br>指定Repository的工厂类</p>\n<p>9)entityManagerFactoryRef<br>实体管理工厂引用名称,对应到@Bean注解对应的方法</p>\n<p>10)transactionManagerRef</p>\n<p>事务管理工厂引用名称,对应到@Bean注解对应的方法</p>\n"},{"title":"Spring Boot中使用Spring Security进行安全控制","url":"https://yangzhiw.github.io/2016/08/17/Security进行安全控制/","content":""},{"title":"JavaWeb基础","url":"https://yangzhiw.github.io/2016/08/16/JavaWeb基础/","content":"<h1 id=\"1,Servlet-生命周期、工作原理\"><a href=\"#1,Servlet-生命周期、工作原理\" class=\"headerlink\" title=\"1,Servlet 生命周期、工作原理\"></a>1,Servlet 生命周期、工作原理</h1><p><a href=\"http://www.cnblogs.com/xuekyo/archive/2013/02/24/2924072.html\" target=\"_blank\" rel=\"external\">点我跳转</a></p>\n<h1 id=\"2,JSP和Servlet的区别\"><a href=\"#2,JSP和Servlet的区别\" class=\"headerlink\" title=\"2,JSP和Servlet的区别\"></a>2,JSP和Servlet的区别</h1><p>jsp经过编译后变成类servlet,<br>jsp由html代码和jsp标签组成,擅长页面显示,servlet擅长流程控制;<br>JSP中嵌入JAVA代码,而Servlet中嵌入HTML代码。</p>\n<h1 id=\"3,JSP的动态include和静态include\"><a href=\"#3,JSP的动态include和静态include\" class=\"headerlink\" title=\"3,JSP的动态include和静态include\"></a>3,JSP的动态include和静态include</h1><p>(1)动态include用jsp:include动作实现,如<jsp:include page=\"abc.jsp\" flush=\"true\">,<br>它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数。会先解析所要包含的页面,解析后和主页面合并一起显示,即先编译后包含。<br>(2)静态include用include伪码实现,不会检查所含文件的变化,适用于包含静态页面,如<%@ include file=”qq.htm” %>,<br>不会提前解析所要包含的页面,先把要显示的页面包含进来,然后统一编译,即先包含后编译。</jsp:include></p>\n<h1 id=\"4,设计模式的6大原则\"><a href=\"#4,设计模式的6大原则\" class=\"headerlink\" title=\"4,设计模式的6大原则\"></a>4,设计模式的6大原则</h1><p>(1)单一职责原则<br> 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;<br> 提高类的可读性,提高系统的可维护性;<br> 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。</p>\n<p>(2)里氏替换原则<br> 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。<br> 子类中可以增加自己特有的方法。<br> 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。<br> 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。</p>\n<p>(3)依赖倒置原则<br>定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。<br>传递依赖关系的三种关系:<br> 接口传递<br> 构造方法传递<br> setter方法传递<br>(4)接口隔离原则<br>定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。<br>接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,<br> 则会造成接口数量过多,使设计复杂化。所以一定要适度。<br>为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,<br> 才能建立最小的依赖关系。<br>提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。<br>(5)迪米特法则<br>定义:一个对象应该对其他对象保持最少的了解。<br>(6)开闭原则<br>定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。</p>\n<h1 id=\"4,Hibernate缓存:一级缓存和二级缓存\"><a href=\"#4,Hibernate缓存:一级缓存和二级缓存\" class=\"headerlink\" title=\"4,Hibernate缓存:一级缓存和二级缓存\"></a>4,Hibernate缓存:一级缓存和二级缓存</h1><p>Hibernate缓存的分类:<br>(1),Session缓存(又称事物缓存),Hibernate内置的,不能卸载;<br>缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。<br>(2)SessionFactory缓存(又称作应用缓存):使用第三方插件,可插拔.<br>缓存范围:缓存被应用范围内的所有session共享,不同的Session可以共享。这些session有可能是并发访问缓存,因此必须对缓存进行更新。<br> 缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用程序范围。</p>\n<p>一级缓存:<br>(1). save()。当session对象调用save()方法保存一个对象后,该对象会被放入到session的缓存中。<br>(2). get()和load()。当session对象调用get()或load()方法从数据库取出一个对象后,该对象也会被放入到session的缓存中。<br>(3). 使用HQL和QBC等从数据库中查询数据。<br>数据从缓存中清除:<br>(1). evit()将指定的持久化对象从缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象。<br>(2). clear()将缓存中的所有持久化对象清除,释放其占用的内存资源。<br>其他缓存操作:<br>(1). contains()判断指定的对象是否存在于缓存中。<br>(2). flush()刷新缓存区的内容,使之与数据库数据保持同步。</p>\n<p>二级缓存:<br>定义:SessionFactory级别的缓存,可以跨越Session存在,可以被多个Session所共享。<br>实现原理:<br>Hibernate如何将数据库中的数据放入到二级缓存中?注意,你可以把缓存看做是一个Map对象,<br>它的Key用于存储对象OID,Value用于存储POJO。首先,当我们使用Hibernate从数据库中查询出数据,<br>获取检索的数据后,Hibernate将检索出来的对象的OID放入缓存中key 中,然后将具体的POJO放入value中,<br>等待下一次再次向数据查询数据时,Hibernate根据你提供的OID先检索一级缓存,若有且配置了二级缓存,则检索二级缓存,<br>如果还没有则才向数据库发送SQL语句,然后将查询出来的对象放入缓存中。</p>\n"},{"title":"计算机网络知识复习","url":"https://yangzhiw.github.io/2016/08/12/计算机网络知识复习/","content":""},{"title":"Spring定时任务","url":"https://yangzhiw.github.io/2016/08/10/spring定时任务/","content":"<h2 id=\"获取昨天时间\"><a href=\"#获取昨天时间\" class=\"headerlink\" title=\"获取昨天时间\"></a>获取昨天时间</h2><pre><code>Calendar c=Calendar.getInstance();\nc.add(Calendar.DAY_OF_MONTH,-1); //日期月是0-11\nc.set(Calendar.HOUR_OF_DAY,0); \nc.set(Calendar.MINUTE,0);\nc.set(Calendar.SECOND,0);\nc.set(Calendar.MILLISECOND,0);\nreturn c.getTime();\n</code></pre><h2 id=\"在类上加上注解\"><a href=\"#在类上加上注解\" class=\"headerlink\" title=\"在类上加上注解\"></a>在类上加上注解</h2><p>@Configuration<br>@EnableScheduling<br>@Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行<br>@Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行<br>@Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次<br>@Scheduled(cron=”<em>/5 </em> <em> </em> <em> </em>“) :通过cron表达式定义规则 </p>\n"},{"title":"获取文件流编码","url":"https://yangzhiw.github.io/2016/08/10/获取文件流的编码/","content":"<h1 id=\"1,获取文件的流\"><a href=\"#1,获取文件的流\" class=\"headerlink\" title=\"1,获取文件的流\"></a>1,获取文件的流</h1><pre><code>InportStream importStream = file.getInputStream();\n</code></pre><h1 id=\"2,把文件流转化为字节流\"><a href=\"#2,把文件流转化为字节流\" class=\"headerlink\" title=\"2,把文件流转化为字节流\"></a>2,把文件流转化为字节流</h1><pre><code>//字节数组输出流\nByteArrayOutputStream baos = new ByteArrayOutputStream();\ntry {\n byte[] buffer = new byte[1024];\n int len;\n while ((len = inputStream.read(buffer)) > -1) {\n baos.write(buffer, 0, len);\n }\n baos.flush();\n}catch(IOException e){\n e.printStackTrace();\n}\nreturn new ByteArrayInputStream(baos.toByteArray());\n</code></pre><h1 id=\"3,根据字节流的判断文件的编码\"><a href=\"#3,根据字节流的判断文件的编码\" class=\"headerlink\" title=\"3,根据字节流的判断文件的编码\"></a>3,根据字节流的判断文件的编码</h1><pre><code>//默认编码\nString charset = "GBK";\nbyte[] first3Bytes = new byte[3];\n//缓存流\nBufferedInputStream bis = new BufferedInputStream(inputStream1);\ntry {\n boolean checked = false;\n //标记\n bis.mark(0);\n //读取文件的前3个字符\n int read = bis.read(first3Bytes, 0, 3);\n if (read == -1) return charset;\n if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {\n charset = "UTF-16LE";\n checked = true;\n } else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {\n charset = "UTF-16BE";\n checked = true;\n } else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) {\n charset = "UTF-8";\n checked = true;\n }\n bis.reset();\n if (!checked) {\n\n int loc = 0;\n while ((read = bis.read()) != -1) {\n loc++;\n if (read >= 0xF0) break;\n if (0x80 <= read && read <= 0xBF) // 单独出现BF以下的,也算是GBK\n break;\n if (0xC0 <= read && read <= 0xDF) {\n read = bis.read();\n if (0x80 <= read && read <= 0xBF) // 双字节 (0xC0 - 0xDF) (0x80\n continue;\n else break;\n } else if (0xE0 <= read && read <= 0xEF) {// 也有可能出错,但是几率较小\n read = bis.read();\n if (0x80 <= read && read <= 0xBF) {\n read = bis.read();\n if (0x80 <= read && read <= 0xBF) {\n charset = "UTF-8";\n break;\n } else break;\n } else break;\n }\n }\n }\n} catch (Exception e) {\n e.printStackTrace();\n} finally {\n try {\n bis.close();\n } catch (IOException e) {\n e.printStackTrace();\n }\n}\n</code></pre>"},{"title":"java 复习资料","url":"https://yangzhiw.github.io/2016/08/01/java-基础题/","content":"<h1 id=\"java基础\"><a href=\"#java基础\" class=\"headerlink\" title=\"java基础\"></a>java基础</h1><p>1,面向对象和面向过程的区别<br>2,java的三大特性</p>\n<hr>\n<pre><code>封装,继承,多态\n</code></pre><p>3,OverLoad与Override的区别<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"> Override(重写,覆盖) </div><div class=\"line\">方法名、参数、返回值相同。</div><div class=\"line\">子类方法不能缩小父类方法的访问权限。</div><div class=\"line\">子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。</div><div class=\"line\">存在于父类和子类之间。</div><div class=\"line\">方法被定义为final不能被重写。</div><div class=\"line\"></div><div class=\"line\"> Overload(重载,过载)</div><div class=\"line\">参数类型、个数、顺序至少有一个不相同。 </div><div class=\"line\">不能重载只有返回值不同的方法名。</div><div class=\"line\">存在于父类和子类、同类中。</div></pre></td></tr></table></figure></p>\n<p>4,构造器不能被修饰Override<br>5,访问控制符public,protected,private,以及默认的区别<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">作用域 当前类 同包 子类 其他</div><div class=\"line\">public √ √ √ √</div><div class=\"line\">protected √ √ √ ×</div><div class=\"line\">default √ √ × ×</div><div class=\"line\">private √ × × ×</div></pre></td></tr></table></figure></p>\n<p>6,String和StringBuffer、StringBuilder的区别<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">可变与不可变</div><div class=\"line\">String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。</div><div class=\"line\">private final char value[];</div><div class=\"line\"></div><div class=\"line\">StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符</div><div class=\"line\">数组保存字符串,如下就是,可知这两种对象都是可变的。</div><div class=\"line\"></div><div class=\"line\">char[] value;</div><div class=\"line\">线程是否安全</div><div class=\"line\">StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。</div><div class=\"line\">StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。</div></pre></td></tr></table></figure></p>\n<p>7,抽象类和接口的区别<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"number\">1</span>)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"number\">2</span>)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"number\">3</span>)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"number\">4</span>)一个类只能继承一个抽象类,而一个类却可以实现多个接口。</div></pre></td></tr></table></figure></p>\n<p>8,自动装箱与拆箱<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\">基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE <span class=\"number\">5.0</span>开始提供的功能。 </div><div class=\"line\">基本数据与对象的区别</div><div class=\"line\">如:int t = <span class=\"number\">1</span>; t. 后面是没有方法滴。</div><div class=\"line\"></div><div class=\"line\"> Integer t =<span class=\"number\">1</span>; t. 后面就有很多方法可让你调用了。</div><div class=\"line\"></div><div class=\"line\">Integer i = <span class=\"number\">100</span>; // 自动装箱</div><div class=\"line\">相当于编译器自动为您作以下的语法编译:Integer i = Integer.valueOf(<span class=\"number\">100</span>);</div><div class=\"line\">Integer i = <span class=\"number\">10</span>; //装箱 </div><div class=\"line\">int t = i; //拆箱,实际上执行了 int t = i.intValue(); </div><div class=\"line\"></div><div class=\"line\">注意:integer值得默认大小是<span class=\"bullet\">-127</span><span class=\"bullet\">-128</span></div></pre></td></tr></table></figure></p>\n<p>7,泛型<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">泛型是Java SE <span class=\"number\">1.5</span>的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,</div><div class=\"line\">类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,</div><div class=\"line\">将泛型java代码直接转换成普通java字节码。</div><div class=\"line\"> 类型擦除的主要过程如下:</div><div class=\"line\"> <span class=\"number\">1.</span>将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。</div><div class=\"line\"> <span class=\"number\">2.</span>移除所有的类型参数。</div></pre></td></tr></table></figure></p>\n<p>8,Java中的集合类及其关系图<br>关系图<br><img src=\"/2016/08/01/java-基础题/java_collection.jpg\" alt=\"微服务架构图\" title=\"微服务架构图\"><br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"> 上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,</div><div class=\"line\"> 折线边框的是抽象类,比如AbstractCollection,AbstractList,AbstractMap等,</div><div class=\"line\"> 而点线边框的是接口,比如Collection,Iterator,List等。</div><div class=\"line\"> \t \t\t是否有序\t是否允许元素重复</div><div class=\"line\">Collection\t\t否\t\t是</div><div class=\"line\">List\t\t\t是\t\t是</div><div class=\"line\">Set\tAbstractSet\t否\t\t否</div><div class=\"line\"> \tHashSet \t 否\t\t否</div><div class=\"line\"> \tTreeSet\t\t是\t\t否</div><div class=\"line\">Map\tAbstractMap\t否\t使用key-value来映射和存储数据,key必须唯一,value可以重复</div><div class=\"line\"> \tHashMap</div><div class=\"line\"> \tTreeMap\t\t是(用二叉排序树)</div></pre></td></tr></table></figure></p>\n<p>9,HashMap的实现原理<br> 见此链接<br>10,HashTable实现原理<br> 见此链接<br>11,HashMap与HashTable的区别<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div></pre></td><td class=\"code\"><pre><div class=\"line\">第一,继承不同。</div><div class=\"line\"></div><div class=\"line\">public class Hashtable extends Dictionary implements Map</div><div class=\"line\">public class HashMap extends AbstractMap implements Map</div><div class=\"line\">第二</div><div class=\"line\"></div><div class=\"line\">Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,</div><div class=\"line\">可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。</div><div class=\"line\">如果为了要线程安全,可以使用CurrentHashMap</div><div class=\"line\"></div><div class=\"line\">第三</div><div class=\"line\"></div><div class=\"line\">Hashtable中,key和value都不允许出现<span class=\"literal\">null</span>值。</div><div class=\"line\"></div><div class=\"line\">在HashMap中,<span class=\"literal\">null</span>可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为<span class=\"literal\">null</span>。当get()方法返回<span class=\"literal\">null</span>值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为<span class=\"literal\">null</span>。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。</div><div class=\"line\"></div><div class=\"line\">第四,两个遍历方式的内部实现上不同。</div><div class=\"line\"></div><div class=\"line\">Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。</div><div class=\"line\"></div><div class=\"line\">第五</div><div class=\"line\"></div><div class=\"line\">哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。</div><div class=\"line\"></div><div class=\"line\">第六</div><div class=\"line\"></div><div class=\"line\">Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是<span class=\"number\">11</span>,增加的方式是 old*<span class=\"number\">2</span>+<span class=\"number\">1</span>。HashMap中hash数组的默认大小是<span class=\"number\">16</span>,而且一定是<span class=\"number\">2</span>的指数。</div></pre></td></tr></table></figure></p>\n<p>12,ArrayList和vector区别<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"number\">1</span>) Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。 </div><div class=\"line\"><span class=\"number\">2</span>) 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加<span class=\"number\">50</span>%的大小,这样,ArrayList就有利于节约内存空间。</div></pre></td></tr></table></figure></p>\n<p>13,ArrayList和LinkedList区别及使用场景<br>区别<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">ArryList初始化时,elementData数组大小默认为<span class=\"number\">10</span>;</div><div class=\"line\">每次add()时,先调用ensureCapacity()保证数组不会溢出,如果此时已满,会扩展为数组length的<span class=\"number\">1.5</span>倍+<span class=\"number\">1</span>,</div><div class=\"line\">然后用array.copy的方法,将原数组拷贝到新的数组中;线程不安全。</div><div class=\"line\"></div><div class=\"line\">LinkedList是基于双链表实现的:</div><div class=\"line\">使用header的优点是:在任何一个条目(包括第一个和最后一个)都有一个前置条目和一个后置条目,</div><div class=\"line\">因此在LinkedList对象的开始或者末尾进行插入操作没有特殊的地方;</div></pre></td></tr></table></figure></p>\n<p>使用场景<br> (1)查询操作多,ArrayList对象要远优于LinkedList对象;</p>\n<p> (2)修改和删除操作多,LinkedList对象要远优于ArrayList对象;</p>\n<p>14,static和final区别和用途<br> static<br> <figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">修饰变量:静态变量随着类被加载时被完全初始化,在内存中只有一个,并且JVM只会为它分配一次内存,所有类共享此变量。</div><div class=\"line\">修饰方法:在类加载时存在,不依赖任何实例,方法必须实现,不能用abstract修饰。</div><div class=\"line\">修饰代码块:在类加载完之后执行代码块的内容。</div><div class=\"line\"> 父类静态代码块->子类静态代码块->父类非静态代码块->父类构造方法—>子类非静态代码块->子类构造方法</div></pre></td></tr></table></figure></p>\n<p> final<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"> 修饰变量:</div><div class=\"line\"> 编译器常量:类加载是完成初始化,编译后带入到任何计算中,只能基本数据类型。</div><div class=\"line\"> 运行时常量:基本数据类型或引用数据类型,引用不可变,但引用的类型可变。</div><div class=\"line\">修饰方法:方法不能被继承,不能被子类修改。</div><div class=\"line\">修饰类:不能被继承。</div><div class=\"line\">修饰形参:final形参不可变。</div></pre></td></tr></table></figure></p>\n<p>15,HashMap和ConcurrentHashMap的区别<br>HashMap不是线程安全的,ConcurrentHashMap是线程安全的。<br>ConcurrentHashMap将整个Hash桶进行了分段segment,每个segment上面都有锁的存在。<br>ConcurrentHashMap的锁的粒度越细,并发性能越好。</p>\n<p>16,线程安全<br>定义:类的行为与其的规范一致。<br>如何保证线程安全:<br> 对变量使用validate<br> 对程序进行加锁<br>17,多线程如何进行信息交互<br>Object中的方法,wait,notify(),notifyAll()</p>\n<p>18,多线程共用一个变量需要注意什么<br>在线程对象runnable中定义了全局变量,run方法会修改该变量时,如果有多个线程同时使用该变量时候,可能有错误发生。<br>ThreadLocal是JDK引入的一种机制,它用于解决线程的共享变量,使用ThreadLocal声明的变量,即使在线程中属于全局变量,<br>针对每个线程来讲,这个变量是独立的。<br>validate变量每次被线程访问时,都会使得线程从主内存中重读该变量的最新值,而该变量发生修改时,也是把修改的值写入到<br>内存中去。</p>\n<p>19,线程池<br>基本组成部分:<br> 线程管理器(ThreadPool) :用户创建并管理线程池,包括创建,摧毁线程池,添加新任务。<br> 工作线程(poolwork):线程池中的线程,在没有任务时,处于等待状态,可以循环使用。<br> 任务接口(Task):每个任务必须实现的接口,以供工作线程调度的执行,它主要规定了任务的入口,<br> 任务完成的收尾工作,任务的执行状态等。<br> 任务队列(Taskqueue):用于存放没有处理的任务,提供一种缓存机制。</p>\n"},{"title":"spring AOP 注解开发","url":"https://yangzhiw.github.io/2016/07/28/spring-AOP-注解开发/","content":"<h1 id=\"1-简介\"><a href=\"#1-简介\" class=\"headerlink\" title=\"1.简介\"></a>1.简介</h1><p>AOP主要包含了通知、切点和连接点等术语,介绍如下:</p>\n<h2 id=\"通知(advice)\"><a href=\"#通知(advice)\" class=\"headerlink\" title=\"通知(advice)\"></a>通知(advice)</h2><p>通知定义了切面是什么以及何时调用,何时调用包含以下几种<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">Before 在方法被调用之前调用通知</div><div class=\"line\">After 在方法完成之后调用通知,无论方法执行是否成功</div><div class=\"line\">After-returning 在方法成功执行之后调用通知</div><div class=\"line\">After-throwing 在方法抛出异常后调用通知</div><div class=\"line\">Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为</div></pre></td></tr></table></figure></p>\n<h2 id=\"切点-PointCut\"><a href=\"#切点-PointCut\" class=\"headerlink\" title=\"切点(PointCut)\"></a>切点(PointCut)</h2><p>通知定义了切面的什么和何时,切点定义了何处,切点的定义会匹配通知所要织入的一个或多个连接点,<br>我们通常使用明确的类的方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称来指定这些切点。</p>\n<h2 id=\"连接点-JoinPoint\"><a href=\"#连接点-JoinPoint\" class=\"headerlink\" title=\"连接点(JoinPoint)\"></a>连接点(JoinPoint)</h2><p>连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至是修改一个字段时,<br>切面代码可以利用这些连接点插入到应用的正常流程中,并添加新的行为,如日志、安全、事务、缓存等。<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">joinPoint.getSignature().getDeclaringTypeName() 可以获取到调用方法的类名(包括包名),</div><div class=\"line\">joinPoint.getSignature().getName() 可以获取方法名,</div><div class=\"line\">Arrays.toString(joinPoint.getArgs()) 得到的是方法调用的参数列表,</div><div class=\"line\">joinPoint.proceed() 可以得到方法的返回结果</div></pre></td></tr></table></figure></p>\n<h1 id=\"2-注解开发\"><a href=\"#2-注解开发\" class=\"headerlink\" title=\"2.注解开发\"></a>2.注解开发</h1><p>声明一个切面,只需要在类名上添加@Aspect属性即可,具体的连接点,我们用@Pointcut和@Before、@After等标注。<br>在声明前 我们需要依赖配置pom<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"></div><div class=\"line\"><dependency<span class=\"string\">></span></div><div class=\"line\"> <groupId>org.aspectj</groupId></div><div class=\"line\"> <artifactId>aspectjrt</artifactId></div><div class=\"line\"> <version>1.6.11</version></div><div class=\"line\"></dependency></div><div class=\"line\"><dependency></div><div class=\"line\"> <groupId>org.aspectj</groupId></div><div class=\"line\"> <artifactId>aspectjweaver</artifactId></div><div class=\"line\"> <version>1.6.11</version></div><div class=\"line\"></dependency></div></pre></td></tr></table></figure></p>\n<p>例子<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div></pre></td><td class=\"code\"><pre><div class=\"line\">package com.ganji.demo.service.aspect;</div><div class=\"line\"></div><div class=\"line\">import org.aspectj.lang.ProceedingJoinPoint;</div><div class=\"line\">import org.aspectj.lang.annotation.*;</div><div class=\"line\">import org.springframework.stereotype.Service;</div><div class=\"line\"></div><div class=\"line\">/**</div><div class=\"line\"> * Created by admin on <span class=\"number\">2015</span>/<span class=\"number\">9</span>/<span class=\"number\">2.</span></div><div class=\"line\"> */</div><div class=\"line\">@Aspect</div><div class=\"line\">@Service</div><div class=\"line\">public class XmlAopDemoUserLog {</div><div class=\"line\"></div><div class=\"line\">// 配置切点 及要传的参数 </div><div class=\"line\"> @Pointcut(<span class=\"string\">\"execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)\"</span>)</div><div class=\"line\"> public void pointCut(int id)</div><div class=\"line\"> {</div><div class=\"line\"></div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">// 配置连接点 方法开始执行时通知</div><div class=\"line\"> @Before(<span class=\"string\">\"pointCut(id)\"</span>)</div><div class=\"line\"> public void beforeLog(int id) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"开始执行前置通知 日志记录:\"</span>+id);</div><div class=\"line\"> }</div><div class=\"line\">// 方法执行完后通知</div><div class=\"line\"> @After(<span class=\"string\">\"pointCut(id)\"</span>)</div><div class=\"line\"> public void afterLog(int id) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"开始执行后置通知 日志记录:\"</span>+id);</div><div class=\"line\"> }</div><div class=\"line\">// 执行成功后通知</div><div class=\"line\"> @AfterReturning(<span class=\"string\">\"pointCut(id)\"</span>)</div><div class=\"line\"> public void afterReturningLog(int id) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"方法成功执行后通知 日志记录:\"</span>+id);</div><div class=\"line\"> }</div><div class=\"line\">// 抛出异常后通知</div><div class=\"line\"> @AfterThrowing(<span class=\"string\">\"pointCut(id)\"</span>)</div><div class=\"line\"> public void afterThrowingLog(int id) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"方法抛出异常后执行通知 日志记录\"</span>+id);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">// 环绕通知</div><div class=\"line\"> @Around(<span class=\"string\">\"pointCut(id)\"</span>)</div><div class=\"line\"> public Object aroundLog(ProceedingJoinPoint joinpoint,int id) {</div><div class=\"line\"> Object result = <span class=\"literal\">null</span>;</div><div class=\"line\"> try {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"环绕通知开始 日志记录\"</span>+id);</div><div class=\"line\"> long start = System.currentTimeMillis();</div><div class=\"line\"></div><div class=\"line\"> //有返回参数 则需返回值</div><div class=\"line\"> result = joinpoint.proceed();</div><div class=\"line\"></div><div class=\"line\"> long end = System.currentTimeMillis();</div><div class=\"line\"> System.out.println(<span class=\"string\">\"总共执行时长\"</span> + (end - start) + <span class=\"string\">\" 毫秒\"</span>);</div><div class=\"line\"> System.out.println(<span class=\"string\">\"环绕通知结束 日志记录\"</span>);</div><div class=\"line\"> } catch (Throwable t) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"出现错误\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> return result;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h1 id=\"AOP切面中的同步问题\"><a href=\"#AOP切面中的同步问题\" class=\"headerlink\" title=\"AOP切面中的同步问题\"></a>AOP切面中的同步问题</h1><p>在WebLogAspect切面中,分别通过doBefore和doAfterReturning两个独立函数实现了切点头部和切点返回后执行的内容,<br>若我们想统计请求的处理时间,就需要在doBefore处记录时间,并在doAfterReturning处通过当前时间与开始处记录的时间计算<br>得到请求处理的消耗时间。<br>那么我们是否可以在WebLogAspect切面中定义一个成员变量来给doBefore和doAfterReturning一起访问呢?是否会有同步问题呢?<br>的确,直接在这里定义基本类型会有同步问题,所以我们可以引入ThreadLocal对象,像下面这样进行记录:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div></pre></td><td class=\"code\"><pre><div class=\"line\">@Aspect</div><div class=\"line\">@Component</div><div class=\"line\">public class WebLogAspect {</div><div class=\"line\"></div><div class=\"line\"> private Logger logger = Logger.getLogger(getClass());</div><div class=\"line\"></div><div class=\"line\"> ThreadLocal<Long> startTime = new ThreadLocal<>();</div><div class=\"line\"></div><div class=\"line\"> @Pointcut(<span class=\"string\">\"execution(public * com.juzi.web..*.*(..))\"</span>)</div><div class=\"line\"> public void webLog(){}</div><div class=\"line\"></div><div class=\"line\"> @Before(<span class=\"string\">\"webLog()\"</span>)</div><div class=\"line\"> public void doBefore(JoinPoint joinPoint) throws Throwable {</div><div class=\"line\"> startTime.set(System.currentTimeMillis());</div><div class=\"line\"></div><div class=\"line\"> // 省略日志记录内容</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> @AfterReturning(returning = <span class=\"string\">\"ret\"</span>, pointcut = <span class=\"string\">\"webLog()\"</span>)</div><div class=\"line\"> public void doAfterReturning(Object ret) throws Throwable {</div><div class=\"line\"> // 处理完请求,返回内容</div><div class=\"line\"> logger.info(<span class=\"string\">\"RESPONSE : \"</span> + ret);</div><div class=\"line\"> logger.info(<span class=\"string\">\"SPEND TIME : \"</span> + (System.currentTimeMillis() - startTime.get()));</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h1 id=\"AOP切面的优先级\"><a href=\"#AOP切面的优先级\" class=\"headerlink\" title=\"AOP切面的优先级\"></a>AOP切面的优先级</h1><p>由于通过AOP实现,程序得到了很好的解耦,但是也会带来一些问题,比如:我们可能会对Web层做多个切面,校验用户,<br>校验头信息等等,这个时候经常会碰到切面的处理顺序问题。</p>\n<p>所以,我们需要定义每个切面的优先级,我们需要@Order(i)注解来标识切面的优先级。i的值越小,优先级越高。<br>假设我们还有一个切面是CheckNameAspect用来校验name必须为didi,我们为其设置@Order(10),<br>而上文中WebLogAspect设置为@Order(5),所以WebLogAspect有更高的优先级,这个时候执行顺序是这样的:</p>\n<p>在@Before中优先执行@Order(5)的内容,再执行@Order(10)的内容<br>在@After和@AfterReturning中优先执行@Order(10)的内容,再执行@Order(5)的内容<br>所以我们可以这样子总结:</p>\n<p>在切入点前的操作,按order的值由小到大执行<br>在切入点后的操作,按order的值由大到小执行</p>\n"},{"title":"Docker 应用","url":"https://yangzhiw.github.io/2016/07/27/Docker-应用/","content":"<h1 id=\"应用Docker部署\"><a href=\"#应用Docker部署\" class=\"headerlink\" title=\"应用Docker部署\"></a>应用Docker部署</h1><p>在项目的根目录下建立一个Dockerfile文件<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div></pre></td><td class=\"code\"><pre><div class=\"line\">FROM maven:<span class=\"number\">3.3</span><span class=\"number\">.3</span> </div><div class=\"line\"> </div><div class=\"line\">ADD pom.xml /tmp/build/ </div><div class=\"line\">RUN cd /tmp/build && mvn -q dependency:resolve </div><div class=\"line\"> </div><div class=\"line\">ADD src /tmp/build/src </div><div class=\"line\"> <span class=\"comment\">#构建应用 </span></div><div class=\"line\">RUN cd /tmp/build && mvn -q -DskipTests=<span class=\"literal\">true</span> package \\ </div><div class=\"line\"> <span class=\"comment\">#拷贝编译结果到指定目录 </span></div><div class=\"line\"> && mv target/*.jar /app.jar \\ </div><div class=\"line\"> <span class=\"comment\">#清理编译痕迹 </span></div><div class=\"line\"> && cd / && rm -rf /tmp/build </div><div class=\"line\"> </div><div class=\"line\">VOLUME /tmp </div><div class=\"line\">EXPOSE <span class=\"number\">8080</span> </div><div class=\"line\">ENTRYPOINT [<span class=\"string\">\"java\"</span>,<span class=\"string\">\"-Djava.security.egd=file:/dev/./urandom\"</span>,<span class=\"string\">\"-jar\"</span>,<span class=\"string\">\"/app.jar\"</span>]</div></pre></td></tr></table></figure></p>\n<p>因为 Spring Boot 框架打包的应用是一个包含依赖的 jar 文件,内嵌了 Tomcat 和 Jetty 支持,所以我们只需要使用包含 Java<br>的 Maven 镜像即可,不需要 Tomcat 镜像。<br>为了减少镜像大小,在执行 Maven 构建之后,清理了构建痕迹。<br>在 Dockerfile 文件的最后,使用 ENTRYPOINT 指令执行启动 Java 应用的操作。</p>\n<h1 id=\"构建-Docker-镜像\"><a href=\"#构建-Docker-镜像\" class=\"headerlink\" title=\"构建 Docker 镜像\"></a>构建 Docker 镜像</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">docker build -t docker-demo-spring-boot . //注意后面的 . 表示当前路径下</div></pre></td></tr></table></figure>\n<h1 id=\"从镜像启动容器\"><a href=\"#从镜像启动容器\" class=\"headerlink\" title=\"从镜像启动容器\"></a>从镜像启动容器</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">docker run -d -p <span class=\"number\">8080</span>:<span class=\"number\">8080</span> docker-demo-spring-boot</div></pre></td></tr></table></figure>\n<h1 id=\"完成部署:\"><a href=\"#完成部署:\" class=\"headerlink\" title=\"完成部署:\"></a>完成部署:</h1><p>URL访问,可通过docker ip查看应用的虚拟地址。</p>\n<h1 id=\"Docker-Compose编排\"><a href=\"#Docker-Compose编排\" class=\"headerlink\" title=\"Docker Compose编排\"></a>Docker Compose编排</h1><p>Docker Compose是用于定义和组装运行多容器分布式应用的工具,<br>它提供一个简单的基于YAML语言的docker-compose.yml配置文件。 通常,我们使用docker定义和运行复杂的应用,<br>使用docker compose,在一个文件里定义多容器应用的启动顺序,起到服务编排的作用。</p>\n<h2 id=\"编写-docker-compose-yaml-文件\"><a href=\"#编写-docker-compose-yaml-文件\" class=\"headerlink\" title=\"编写 docker-compose.yaml 文件\"></a>编写 docker-compose.yaml 文件</h2><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"attr\">web:</span> </div><div class=\"line\"><span class=\"attr\"> build:</span> . </div><div class=\"line\"><span class=\"attr\"> ports:</span> </div><div class=\"line\"><span class=\"bullet\"> -</span> <span class=\"string\">\"8080:8080\"</span> </div><div class=\"line\"><span class=\"attr\"> links:</span> </div><div class=\"line\"><span class=\"attr\"> - mongodb:</span>mongodb </div><div class=\"line\"> </div><div class=\"line\"><span class=\"attr\">mongodb:</span> </div><div class=\"line\"><span class=\"attr\"> image:</span> daocloud.io/library/mongo:latest </div><div class=\"line\"><span class=\"attr\"> ports:</span> </div><div class=\"line\"><span class=\"bullet\"> -</span> <span class=\"string\">\"27017:27017\"</span></div></pre></td></tr></table></figure>\n<p>这里以MongoDB数据库提供服务的demo,在该文件中,我们定于了两个服务:</p>\n<pre><code>基于我们应用构建的 docker-demo-java-mongo 镜像,用来提供 Web 服务\n基于 DaoCloud 提供的 MongoDB 镜像,提供存储服务\n通过 links 为 web 关联 mongo 服务\n</code></pre><h2 id=\"启动-Docker-Compose\"><a href=\"#启动-Docker-Compose\" class=\"headerlink\" title=\"启动 Docker Compose\"></a>启动 Docker Compose</h2><pre><code class=\"yaml\">docker-compose up\n</code></pre>\n"},{"title":"spring Boot Cloud2","url":"https://yangzhiw.github.io/2016/07/27/spring-Boot-Cloud2/","content":"<h1 id=\"Spring-Cloud介绍\"><a href=\"#Spring-Cloud介绍\" class=\"headerlink\" title=\"Spring Cloud介绍\"></a>Spring Cloud介绍</h1><p>Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、服务发现、断路器、<br>智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。</p>\n<h1 id=\"Spring-Cloud与Dubbo对比\"><a href=\"#Spring-Cloud与Dubbo对比\" class=\"headerlink\" title=\"Spring Cloud与Dubbo对比\"></a>Spring Cloud与Dubbo对比</h1><p>它们两都具备分布式服务治理相关的功能,都能够提供服务注册、发现、路由、负载均衡等。说到这,Dubbo的功能好像<br>也就这么多了,但是Spring Cloud是提供了一整套企业级分布式云应用的完美解决方案,能够结合Spring Boot,<br>Docker实现快速开发的目的,所以说Dubbo只有Spring Cloud的一部分RPC功能,而且也谈不上谁好谁坏。不过,<br>Dubbo项目现已停止了更新,淘宝内部由hsf替代dubbo,我想这会有更多人倾向Spring Cloud了。<br>从开发角度上说,Dubbo常与Spring、zookeeper结合,而且实现只是通过xml来配置服务地址、名称、端口,<br>代码的侵入性是很小的,相对Spring Cloud,它的实现需要类注解等,多少具有一定侵入性。</p>\n<h1 id=\"Spring-Cloud子项目\"><a href=\"#Spring-Cloud子项目\" class=\"headerlink\" title=\"Spring Cloud子项目\"></a>Spring Cloud子项目</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),之前在第一章节也介绍这些,</div><div class=\"line\">比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud CloudFoundry、Spring Cloud AWS、</div><div class=\"line\">Spring Cloud Security、Spring Cloud Commons、Spring Cloud Zookeeper、Spring Cloud CLI等项目。</div></pre></td></tr></table></figure>\n<h2 id=\"配置服务\"><a href=\"#配置服务\" class=\"headerlink\" title=\"配置服务\"></a>配置服务</h2><p>Spring Cloud通过Netflix OSS的Eureka来实现服务发现,服务发现的主要目的是为了让每个服务之间可以互相通信。<br>Eureka Server为微服务的注册中心。谈到Spring Cloud Netflix,它是Spring Cloud的子项目之一,主要提供的模块包括:<br>服务发现(Eureka),断路器(Hystrix),智能路由(Zuul),客户端负载均衡(Ribbon)等。<br>Spring Cloud使用注解的方式提供了Eureka服务端(@EnableEurekaServer)和客户端(@EnableEurekaClient)。</p>\n<h2 id=\"路由网关\"><a href=\"#路由网关\" class=\"headerlink\" title=\"路由网关\"></a>路由网关</h2><p>路由网关的主要目的是为了让所有的微服务对外只有一个接口,我们只需访问一个网关地址,即可由网关将所有的请求代理<br>到不同的服务中。Spring Cloud是通过Zuul来实现的,支持自动路由映射到在Eureka Server上注册的服务。<br>Spring Cloud提供了注解@EnableZuulProxy来启用路由代理。</p>\n<h2 id=\"负载均衡\"><a href=\"#负载均衡\" class=\"headerlink\" title=\"负载均衡\"></a>负载均衡</h2><p>Spring Cloud提供了Ribbon和Feign作为客户端的负载均衡。在Spring Cloud下,使用Ribbon直接注入一个RestTemplate<br>对象即可,此RestTemplate已做好负载均衡的配置;而使用Feign只需定义个注解,有@FeignClient注解的接口,<br>然后使用@RequestMapping注解在方法上映射远程的REST服务,此方法也是做好了负载均衡配置。</p>\n<h2 id=\"路断器\"><a href=\"#路断器\" class=\"headerlink\" title=\"路断器\"></a>路断器</h2><p>断路器(Circuit Breaker)主要是为了解决当某个方法调用失败的时候,调用后备方法来替代失败的方法,<br>已达到容错/阻止级联错误的功能。Spring Cloud使用@EnableCircuitBreaker来启用断路器支持,<br>使用@HystrixCommand的fallbackMethod来指定后备方法。(@HystrixCommand(fallbackMethod=”fallbackOper”))<br>Spring Cloud还提供了一个控制台来监控断路器的运行情况,通过@EnableHystrixDashboard注解开启。</p>\n<p>Spring Cloud依赖<br><img src=\"/2016/07/27/spring-Boot-Cloud2/spring_cloud.jpg\" alt=\"spring_cloud\" title=\"spring_cloud\"></p>\n"},{"title":"spring Boot Cloud 学习1","url":"https://yangzhiw.github.io/2016/07/27/spring-Boot-Cloud/","content":"<h1 id=\"Spring-简介\"><a href=\"#Spring-简介\" class=\"headerlink\" title=\"Spring 简介\"></a>Spring 简介</h1><img src=\"/2016/07/27/spring-Boot-Cloud/Spring.jpg\" alt=\"Spring Project\" title=\"Spring Project\">\n<p>Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说当你使用maven dependency引入spring jar包时它就在工作了。</p>\n<p>Spring Boot:旨在简化创建产品级的 Spring 应用和服务,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用微服务功能,可以和spring cloud联合部署。</p>\n<p>Spring Framework:即通常所说的spring 框架,是一个开源的Java/Java EE全功能栈应用程序框架,其它spring项目如spring boot也依赖于此框架。</p>\n<p>Spring Cloud:微服务工具包,为开发者提供了在分布式系统的配置管理、服务发现、断路器、智能路由、微代理、控制总线等开发工具包。</p>\n<p>Spring XD:是一种运行时环境(服务器软件,非开发框架),组合spring技术,如spring batch、spring boot、spring data,采集大数据并处理。</p>\n<p>Spring Data:是一个数据访问及操作的工具包,封装了很多种数据及数据库的访问相关技术,包括:jdbc、Redis、MongoDB、Neo4j等。</p>\n<p>Spring Batch:批处理框架,或说是批量任务执行管理器,功能包括任务调度、日志记录/跟踪等。</p>\n<p>Spring Security:是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。</p>\n<p>Spring Integration:面向企业应用集成(EAI/ESB)的编程框架,支持的通信方式包括HTTP、FTP、TCP/UDP、JMS、RabbitMQ、Email等。</p>\n<p>Spring Social:一组工具包,一组连接社交服务API,如Twitter、Facebook、LinkedIn、GitHub等,有几十个。</p>\n<p>Spring AMQP:消息队列操作的工具包,主要是封装了RabbitMQ的操作。</p>\n<p>Spring HATEOAS:是一个用于支持实现超文本驱动的 REST Web 服务的开发库。</p>\n<p>Spring Mobile:是Spring MVC的扩展,用来简化手机上的Web应用开发。</p>\n<p>Spring for Android:是Spring框架的一个扩展,其主要目的在乎简化Android本地应用的开发,提供RestTemplate来访问Rest服务。</p>\n<p>Spring Web Flow:目标是成为管理Web应用页面流程的最佳方案,将页面跳转流程单独管理,并可配置。</p>\n<p>Spring LDAP:是一个用于操作LDAP的Java工具包,基于Spring的JdbcTemplate模式,简化LDAP访问。</p>\n<p>Spring Session:session管理的开发工具包,让你可以把session保存到redis等,进行集群化session管理。</p>\n<p>Spring Web Services:是基于Spring的Web服务框架,提供SOAP服务开发,允许通过多种方式创建Web服务。</p>\n<p>Spring Shell:提供交互式的Shell可让你使用简单的基于Spring的编程模型来开发命令,比如Spring Roo命令。</p>\n<p>Spring Roo:是一种Spring开发的辅助工具,使用命令行操作来生成自动化项目,操作非常类似于Rails。</p>\n<p>Spring Scala:为Scala语言编程提供的spring框架的封装(新的编程语言,Java平台的Scala于2003年底/2004年初发布)。</p>\n<p>Spring BlazeDS Integration:一个开发RIA工具包,可以集成Adobe Flex、BlazeDS、Spring以及Java技术创建RIA。</p>\n<p>Spring Loaded:用于实现java程序和web应用的热部署的开源工具。</p>\n<p>Spring REST Shell:可以调用Rest服务的命令行工具,敲命令行操作Rest服务。</p>\n<a id=\"more\"></a>\n<h1 id=\"Spring-Cloud-项目\"><a href=\"#Spring-Cloud-项目\" class=\"headerlink\" title=\"Spring Cloud 项目\"></a>Spring Cloud 项目</h1><p>目前来说spring主要集中于spring boot(用于开发微服务)和spring cloud相关框架的开发,我们从几张图着手理解,然后再具体介绍</p>\n<img src=\"/2016/07/27/spring-Boot-Cloud/spring_cloud.jpg\" alt=\"微服务架构图\" title=\"微服务架构图\">\n<img src=\"/2016/07/27/spring-Boot-Cloud/cloud.jpg\" alt=\"微服务架构运行图\" title=\"微服务架构运行图\">\n<p>spring cloud子项目包括:</p>\n<p>1, Spring Cloud Config:配置管理开发工具包,可以让你把配置放到远程服务器,目前支持本地存储、Git以及Subversion。</p>\n<p>2, Spring Cloud Bus:事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与Spring Cloud Config联合实现热部署。</p>\n<p>3, Spring Cloud Netflix:针对多种Netflix组件提供的开发工具包,其中包括Eureka、Hystrix、Zuul、Archaius等。</p>\n<p>3.1, Netflix Eureka:云端负载均衡,一个基于 REST 的服务,用于定位服务,以实现云端的负载均衡和中间层服务器的故障转移。</p>\n<p>3.2, Netflix Hystrix:容错管理工具,旨在通过控制服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。</p>\n<p>3.3, Netflix Zuul:边缘服务工具,是提供动态路由,监控,弹性,安全等的边缘服务。</p>\n<p>3.4, Netflix Archaius:配置管理API,包含一系列配置管理API,提供动态类型化属性、线程安全配置操作、轮询框架、回调机制等功能。</p>\n<p>4, Spring Cloud for Cloud Foundry:通过Oauth2协议绑定服务到CloudFoundry,CloudFoundry是VMware推出的开源PaaS云平台。</p>\n<p>5, Spring Cloud Sleuth:日志收集工具包,封装了Dapper,Zipkin和HTrace操作。</p>\n<p>6, Spring Cloud Data Flow:大数据操作工具,通过命令行方式操作数据流。</p>\n<p>7, Spring Cloud Security:安全工具包,为你的应用程序添加安全控制,主要是指OAuth2。</p>\n<p>8, Spring Cloud Consul:封装了Consul操作,consul是一个服务发现与配置工具,与Docker容器可以无缝集成。</p>\n<p>9, Spring Cloud Zookeeper:操作Zookeeper的工具包,用于使用zookeeper方式的服务注册和发现。</p>\n<p>10, Spring Cloud Stream:数据流操作开发包,封装了与Redis,Rabbit、Kafka等发送接收消息。</p>\n<p>11, Spring Cloud CLI:基于 Spring Boot CLI,可以让你以命令行方式快速建立云组件。</p>\n"},{"title":"markDown 的使用","url":"https://yangzhiw.github.io/2016/07/22/markDown/","content":"<h1 id=\"标题\"><a href=\"#标题\" class=\"headerlink\" title=\"标题\"></a>标题</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\"># 一级标题</span></div><div class=\"line\"><span class=\"comment\">## 二级标题</span></div><div class=\"line\">依次类推</div></pre></td></tr></table></figure>\n<h1 id=\"列表\"><a href=\"#列表\" class=\"headerlink\" title=\"列表\"></a>列表</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">在 Markdown 下,列表的显示只需要在文字前加上 - 或 * 即可变为无序列表,</div><div class=\"line\">有序列表则直接在文字前加 <span class=\"number\">1.</span> <span class=\"number\">2.</span> <span class=\"number\">3.</span> 符号要和文字之间加上一个字符的空格。</div></pre></td></tr></table></figure>\n<h1 id=\"引用\"><a href=\"#引用\" class=\"headerlink\" title=\"引用\"></a>引用</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">只需要在文本前加入 > 这种尖括号(大于号)即可</div></pre></td></tr></table></figure>\n<h1 id=\"图片与链接\"><a href=\"#图片与链接\" class=\"headerlink\" title=\"图片与链接\"></a>图片与链接</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">插入链接与插入图片的语法很像,区别在一个 !号</div></pre></td></tr></table></figure>\n<h1 id=\"粗体与斜体\"><a href=\"#粗体与斜体\" class=\"headerlink\" title=\"粗体与斜体\"></a>粗体与斜体</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">Markdown 的粗体和斜体也非常简单,用两个 * 包含一段文本就是粗体的语法,</div><div class=\"line\">用一个 * 包含一段文本就是斜体的语法。</div></pre></td></tr></table></figure>\n<p><strong>我只粗体</strong>,<em>我是斜体</em>。</p>\n<h1 id=\"表格\"><a href=\"#表格\" class=\"headerlink\" title=\"表格\"></a>表格</h1><p>表格是我觉得 Markdown 比较累人的地方,例子如下:<br><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">| Tables | Are | Cool <span class=\"string\">|</span></div><div class=\"line\">| ------------- |:-------------:| -----:|</div><div class=\"line\">| col 3 is | right-aligned | $1600 |</div><div class=\"line\">| col 2 is | centered | $12 |</div><div class=\"line\">| zebra stripes | are neat | $1 |</div></pre></td></tr></table></figure></p>\n<table>\n<thead>\n<tr>\n<th>Tables</th>\n<th style=\"text-align:center\">Are</th>\n<th style=\"text-align:right\">Cool</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>col 3 is</td>\n<td style=\"text-align:center\">right-aligned</td>\n<td style=\"text-align:right\">$1600</td>\n</tr>\n<tr>\n<td>col 2 is</td>\n<td style=\"text-align:center\">centered</td>\n<td style=\"text-align:right\">$12</td>\n</tr>\n<tr>\n<td>zebra stripes</td>\n<td style=\"text-align:center\">are neat</td>\n<td style=\"text-align:right\">$1</td>\n</tr>\n</tbody>\n</table>\n<h1 id=\"分割线\"><a href=\"#分割线\" class=\"headerlink\" title=\"分割线\"></a>分割线</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">分割线的语法只需要另起一行,连续输入三个星号 *** 即可。</div></pre></td></tr></table></figure>\n<hr>\n<h1 id=\"代码框\"><a href=\"#代码框\" class=\"headerlink\" title=\"代码框\"></a>代码框</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">如果你是个程序猿,需要在文章里优雅的引用代码框,在 Markdown 下实现也非常简单,</div><div class=\"line\">只需要用两个 ` 把中间的代码包裹起来.</div><div class=\"line\"></div><div class=\"line\">如 `System.out.println()`</div></pre></td></tr></table></figure>\n<p><code>System.out.println()</code></p>\n"},{"title":"redis集群搭建","url":"https://yangzhiw.github.io/2016/07/22/redis-cluster/","content":"<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">搭建的是一个<span class=\"number\">1</span>主<span class=\"number\">3</span>从的redis+<span class=\"number\">3</span>个哨兵集群的环境,由于是在一台物理机上,所有我们用端口区分。</div><div class=\"line\">物理机IP:<span class=\"number\">192.168</span><span class=\"number\">.0</span><span class=\"number\">.12</span></div><div class=\"line\">主节点master端口:<span class=\"number\">6301</span></div><div class=\"line\">从节点slave1端口:<span class=\"number\">6315</span></div><div class=\"line\">从节点slave2端口:<span class=\"number\">6316</span></div><div class=\"line\">从节点slave3端口:<span class=\"number\">6317</span></div><div class=\"line\">哨兵sentinel1端口:<span class=\"number\">26301</span></div><div class=\"line\">哨兵sentinel2端口:<span class=\"number\">26302</span></div><div class=\"line\">哨兵sentinel3端口:<span class=\"number\">26303</span></div></pre></td></tr></table></figure>\n<h1 id=\"下载redis-amp-amp-复制\"><a href=\"#下载redis-amp-amp-复制\" class=\"headerlink\" title=\"下载redis && 复制\"></a>下载redis && 复制</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">下载redis后然后解压,</div><div class=\"line\">复制 </div><div class=\"line\">cp redis-benchmark redis-cli redis-server redis-sentinel /usr/bin/ <span class=\"comment\">#这个倒是很有用,这样就不用再执行时加上./了,而且可以在任何地方执行</span></div></pre></td></tr></table></figure>\n<h1 id=\"设置内存分配策略(可选,根据服务器的实际情况进行设置)\"><a href=\"#设置内存分配策略(可选,根据服务器的实际情况进行设置)\" class=\"headerlink\" title=\"设置内存分配策略(可选,根据服务器的实际情况进行设置)\"></a>设置内存分配策略(可选,根据服务器的实际情况进行设置)</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">/proc/sys/vm/overcommit_memory</div><div class=\"line\">可选值:<span class=\"number\">0</span>、<span class=\"number\">1</span>、<span class=\"number\">2</span>。</div><div class=\"line\"><span class=\"number\">0</span>, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;</div><div class=\"line\"> 否则,内存申请失败,并把错误返回给应用进程。</div><div class=\"line\"><span class=\"number\">1</span>, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。</div><div class=\"line\"><span class=\"number\">2</span>, 表示内核允许分配超过所有物理内存和交换空间总和的内存</div></pre></td></tr></table></figure>\n<h1 id=\"开启redis端口,修改防火墙配置文件\"><a href=\"#开启redis端口,修改防火墙配置文件\" class=\"headerlink\" title=\"开启redis端口,修改防火墙配置文件\"></a>开启redis端口,修改防火墙配置文件</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"> vi /etc/sysconfig/iptables </div><div class=\"line\">加入端口配置</div><div class=\"line\"><span class=\"bullet\"> -</span>A RH-Firewall<span class=\"bullet\">-1</span>-INPUT -m state --state NEW -m tcp -p tcp --dport <span class=\"number\">6379</span> -j ACCEPT </div><div class=\"line\">重新加载规则</div><div class=\"line\"> service iptables restart</div></pre></td></tr></table></figure>\n<h1 id=\"配置redis-config文件\"><a href=\"#配置redis-config文件\" class=\"headerlink\" title=\"配置redis.config文件\"></a>配置redis.config文件</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div><div class=\"line\">88</div><div class=\"line\">89</div><div class=\"line\">90</div><div class=\"line\">91</div><div class=\"line\">92</div><div class=\"line\">93</div><div class=\"line\">94</div><div class=\"line\">95</div><div class=\"line\">96</div><div class=\"line\">97</div><div class=\"line\">98</div><div class=\"line\">99</div><div class=\"line\">100</div><div class=\"line\">101</div><div class=\"line\">102</div><div class=\"line\">103</div><div class=\"line\">104</div><div class=\"line\">105</div><div class=\"line\">106</div><div class=\"line\">107</div><div class=\"line\">108</div><div class=\"line\">109</div><div class=\"line\">110</div><div class=\"line\">111</div><div class=\"line\">112</div><div class=\"line\">113</div><div class=\"line\">114</div><div class=\"line\">115</div><div class=\"line\">116</div><div class=\"line\">117</div><div class=\"line\">118</div><div class=\"line\">119</div><div class=\"line\">120</div><div class=\"line\">121</div><div class=\"line\">122</div><div class=\"line\">123</div><div class=\"line\">124</div><div class=\"line\">125</div><div class=\"line\">126</div><div class=\"line\">127</div><div class=\"line\">128</div><div class=\"line\">129</div><div class=\"line\">130</div><div class=\"line\">131</div><div class=\"line\">132</div><div class=\"line\">133</div><div class=\"line\">134</div><div class=\"line\">135</div><div class=\"line\">136</div><div class=\"line\">137</div><div class=\"line\">138</div><div class=\"line\">139</div><div class=\"line\">140</div><div class=\"line\">141</div><div class=\"line\">142</div><div class=\"line\">143</div><div class=\"line\">144</div><div class=\"line\">145</div><div class=\"line\">146</div><div class=\"line\">147</div><div class=\"line\">148</div><div class=\"line\">149</div><div class=\"line\">150</div><div class=\"line\">151</div><div class=\"line\">152</div><div class=\"line\">153</div><div class=\"line\">154</div><div class=\"line\">155</div><div class=\"line\">156</div><div class=\"line\">157</div><div class=\"line\">158</div><div class=\"line\">159</div><div class=\"line\">160</div><div class=\"line\">161</div><div class=\"line\">162</div><div class=\"line\">163</div><div class=\"line\">164</div><div class=\"line\">165</div><div class=\"line\">166</div><div class=\"line\">167</div><div class=\"line\">168</div><div class=\"line\">169</div><div class=\"line\">170</div><div class=\"line\">171</div><div class=\"line\">172</div><div class=\"line\">173</div><div class=\"line\">174</div><div class=\"line\">175</div><div class=\"line\">176</div><div class=\"line\">177</div><div class=\"line\">178</div><div class=\"line\">179</div><div class=\"line\">180</div><div class=\"line\">181</div><div class=\"line\">182</div><div class=\"line\">183</div><div class=\"line\">184</div><div class=\"line\">185</div><div class=\"line\">186</div><div class=\"line\">187</div><div class=\"line\">188</div><div class=\"line\">189</div><div class=\"line\">190</div><div class=\"line\">191</div><div class=\"line\">192</div><div class=\"line\">193</div><div class=\"line\">194</div><div class=\"line\">195</div><div class=\"line\">196</div><div class=\"line\">197</div><div class=\"line\">198</div><div class=\"line\">199</div><div class=\"line\">200</div><div class=\"line\">201</div><div class=\"line\">202</div><div class=\"line\">203</div><div class=\"line\">204</div><div class=\"line\">205</div><div class=\"line\">206</div><div class=\"line\">207</div><div class=\"line\">208</div><div class=\"line\">209</div><div class=\"line\">210</div><div class=\"line\">211</div><div class=\"line\">212</div><div class=\"line\">213</div><div class=\"line\">214</div><div class=\"line\">215</div><div class=\"line\">216</div><div class=\"line\">217</div><div class=\"line\">218</div><div class=\"line\">219</div><div class=\"line\">220</div><div class=\"line\">221</div><div class=\"line\">222</div><div class=\"line\">223</div><div class=\"line\">224</div><div class=\"line\">225</div><div class=\"line\">226</div><div class=\"line\">227</div><div class=\"line\">228</div><div class=\"line\">229</div><div class=\"line\">230</div><div class=\"line\">231</div><div class=\"line\">232</div><div class=\"line\">233</div><div class=\"line\">234</div><div class=\"line\">235</div><div class=\"line\">236</div><div class=\"line\">237</div><div class=\"line\">238</div><div class=\"line\">239</div><div class=\"line\">240</div><div class=\"line\">241</div><div class=\"line\">242</div><div class=\"line\">243</div><div class=\"line\">244</div><div class=\"line\">245</div><div class=\"line\">246</div><div class=\"line\">247</div><div class=\"line\">248</div><div class=\"line\">249</div><div class=\"line\">250</div><div class=\"line\">251</div><div class=\"line\">252</div><div class=\"line\">253</div><div class=\"line\">254</div><div class=\"line\">255</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"number\">1</span>、主节点master的配置文件redis_master_6301.config:</div><div class=\"line\"><span class=\"comment\"># Redis configuration file example</span></div><div class=\"line\"><span class=\"comment\">################################## INCLUDES ###################################</span></div><div class=\"line\"><span class=\"comment\"># include /path/to/local.conf</span></div><div class=\"line\"><span class=\"comment\"># include /path/to/other.conf</span></div><div class=\"line\"><span class=\"comment\">################################ GENERAL #####################################</span></div><div class=\"line\">daemonize <span class=\"literal\">yes</span></div><div class=\"line\">pidfile ./run/redis_slaver1_6315.pid</div><div class=\"line\">port <span class=\"number\">6301</span></div><div class=\"line\">tcp-backlog <span class=\"number\">511</span></div><div class=\"line\"><span class=\"comment\"># bind 192.168.1.100 10.0.0.1</span></div><div class=\"line\"><span class=\"comment\"># bind 127.0.0.1</span></div><div class=\"line\"><span class=\"comment\"># unixsocket /tmp/redis.sock</span></div><div class=\"line\"><span class=\"comment\"># unixsocketperm 700</span></div><div class=\"line\">timeout <span class=\"number\">0</span></div><div class=\"line\">tcp-keepalive <span class=\"number\">0</span></div><div class=\"line\">loglevel notice</div><div class=\"line\">logfile <span class=\"string\">\"./run/logs/log_master_6301.log\"</span></div><div class=\"line\">databases <span class=\"number\">16</span></div><div class=\"line\"><span class=\"comment\">################################ SNAPSHOTTING ################################</span></div><div class=\"line\">save <span class=\"string\">\"\"</span></div><div class=\"line\"><span class=\"comment\"># save 900 1</span></div><div class=\"line\"><span class=\"comment\"># save 300 10</span></div><div class=\"line\"><span class=\"comment\"># save 60 10000</span></div><div class=\"line\">stop-writes-on-bgsave-error <span class=\"literal\">yes</span></div><div class=\"line\">rdbcompression <span class=\"literal\">yes</span></div><div class=\"line\">rdbchecksum <span class=\"literal\">no</span></div><div class=\"line\">dbfilename dump_6301.rdb</div><div class=\"line\">dir ./run/data</div><div class=\"line\"><span class=\"comment\">################################# REPLICATION #################################</span></div><div class=\"line\">slave-serve-stale-data <span class=\"literal\">yes</span></div><div class=\"line\">slave-read-only <span class=\"literal\">yes</span></div><div class=\"line\">repl-diskless-sync <span class=\"literal\">no</span></div><div class=\"line\">repl-diskless-sync-delay <span class=\"number\">5</span></div><div class=\"line\"><span class=\"comment\"># repl-ping-slave-period 10</span></div><div class=\"line\"><span class=\"comment\"># repl-timeout 60</span></div><div class=\"line\">repl-disable-tcp-nodelay <span class=\"literal\">no</span></div><div class=\"line\"><span class=\"comment\"># repl-backlog-size 1mb</span></div><div class=\"line\"><span class=\"comment\"># repl-backlog-ttl 3600</span></div><div class=\"line\">slave-priority <span class=\"number\">100</span></div><div class=\"line\"><span class=\"comment\"># min-slaves-to-write 3</span></div><div class=\"line\"><span class=\"comment\"># min-slaves-max-lag 10</span></div><div class=\"line\"><span class=\"comment\">################################## SECURITY ###################################</span></div><div class=\"line\"><span class=\"comment\"># rename-command CONFIG \"\"</span></div><div class=\"line\"><span class=\"comment\">################################### LIMITS ####################################</span></div><div class=\"line\"><span class=\"comment\"># maxclients 10000</span></div><div class=\"line\"><span class=\"comment\"># maxmemory <bytes></span></div><div class=\"line\"><span class=\"comment\"># maxmemory-policy noeviction</span></div><div class=\"line\"><span class=\"comment\"># maxmemory-samples 5</span></div><div class=\"line\"><span class=\"comment\">############################## APPEND ONLY MODE ###############################</span></div><div class=\"line\">appendonly <span class=\"literal\">no</span></div><div class=\"line\">appendfilename <span class=\"string\">\"appendonly_6301.aof\"</span></div><div class=\"line\">appendfsync <span class=\"literal\">no</span></div><div class=\"line\"><span class=\"literal\">no</span>-appendfsync-on-rewrite <span class=\"literal\">no</span></div><div class=\"line\">auto-aof-rewrite-percentage <span class=\"number\">100</span></div><div class=\"line\">auto-aof-rewrite-min-size <span class=\"number\">64</span>mb</div><div class=\"line\">aof-load-truncated <span class=\"literal\">yes</span></div><div class=\"line\"><span class=\"comment\">################################ LUA SCRIPTING ###############################</span></div><div class=\"line\">lua-time-limit <span class=\"number\">5000</span></div><div class=\"line\"><span class=\"comment\">################################ REDIS CLUSTER ###############################</span></div><div class=\"line\"><span class=\"comment\"># cluster-enabled yes</span></div><div class=\"line\"><span class=\"comment\"># cluster-config-file nodes-6379.conf</span></div><div class=\"line\"><span class=\"comment\"># cluster-node-timeout 15000</span></div><div class=\"line\"><span class=\"comment\"># cluster-slave-validity-factor 10</span></div><div class=\"line\"><span class=\"comment\"># cluster-migration-barrier 1</span></div><div class=\"line\"><span class=\"comment\"># cluster-require-full-coverage yes</span></div><div class=\"line\"><span class=\"comment\">################################## SLOW LOG ###################################</span></div><div class=\"line\">slowlog-log-slower-than <span class=\"number\">10000</span></div><div class=\"line\">slowlog-max-len <span class=\"number\">128</span></div><div class=\"line\"><span class=\"comment\">################################ LATENCY MONITOR ##############################</span></div><div class=\"line\">latency-monitor-threshold <span class=\"number\">0</span></div><div class=\"line\"><span class=\"comment\">############################# EVENT NOTIFICATION ##############################</span></div><div class=\"line\">notify-keyspace-events <span class=\"string\">\"\"</span></div><div class=\"line\"><span class=\"comment\">############################### ADVANCED CONFIG ###############################</span></div><div class=\"line\">hash-max-ziplist-entries <span class=\"number\">512</span></div><div class=\"line\">hash-max-ziplist-value <span class=\"number\">64</span></div><div class=\"line\">list-max-ziplist-entries <span class=\"number\">512</span></div><div class=\"line\">list-max-ziplist-value <span class=\"number\">64</span></div><div class=\"line\">set-max-intset-entries <span class=\"number\">512</span></div><div class=\"line\">zset-max-ziplist-entries <span class=\"number\">128</span></div><div class=\"line\">zset-max-ziplist-value <span class=\"number\">64</span></div><div class=\"line\">hll-sparse-max-bytes <span class=\"number\">3000</span></div><div class=\"line\">activerehashing <span class=\"literal\">yes</span></div><div class=\"line\">client-output-buffer-limit normal <span class=\"number\">0</span> <span class=\"number\">0</span> <span class=\"number\">0</span></div><div class=\"line\">client-output-buffer-limit slave <span class=\"number\">256</span>mb <span class=\"number\">64</span>mb <span class=\"number\">60</span></div><div class=\"line\">client-output-buffer-limit pubsub <span class=\"number\">32</span>mb <span class=\"number\">8</span>mb <span class=\"number\">60</span></div><div class=\"line\">hz <span class=\"number\">10</span></div><div class=\"line\">aof-rewrite-incremental-fsync <span class=\"literal\">yes</span></div><div class=\"line\"><span class=\"number\">2</span>、从节点slave1的配置文件redis_slave_6315.config:</div><div class=\"line\"><span class=\"comment\"># Redis configuration file example</span></div><div class=\"line\"><span class=\"comment\">################################## INCLUDES ###################################</span></div><div class=\"line\"><span class=\"comment\"># include /path/to/local.conf</span></div><div class=\"line\"><span class=\"comment\"># include /path/to/other.conf</span></div><div class=\"line\"><span class=\"comment\">################################ GENERAL #####################################</span></div><div class=\"line\">daemonize <span class=\"literal\">yes</span></div><div class=\"line\">pidfile ./run/redis_slaver1_6315.pid</div><div class=\"line\">port <span class=\"number\">6315</span></div><div class=\"line\">tcp-backlog <span class=\"number\">511</span></div><div class=\"line\"><span class=\"comment\"># bind 192.168.1.100 10.0.0.1</span></div><div class=\"line\"><span class=\"comment\"># bind 127.0.0.1</span></div><div class=\"line\"><span class=\"comment\"># unixsocket /tmp/redis.sock</span></div><div class=\"line\"><span class=\"comment\"># unixsocketperm 700</span></div><div class=\"line\">timeout <span class=\"number\">0</span></div><div class=\"line\">tcp-keepalive <span class=\"number\">0</span></div><div class=\"line\">loglevel notice</div><div class=\"line\">logfile <span class=\"string\">\"./run/logs/log_slaver1_6315.log\"</span></div><div class=\"line\">databases <span class=\"number\">16</span></div><div class=\"line\"><span class=\"comment\">################################ SNAPSHOTTING ################################</span></div><div class=\"line\">save <span class=\"string\">\"\"</span></div><div class=\"line\"><span class=\"comment\"># save 900 1</span></div><div class=\"line\"><span class=\"comment\"># save 300 10</span></div><div class=\"line\"><span class=\"comment\"># save 60 10000</span></div><div class=\"line\">stop-writes-on-bgsave-error <span class=\"literal\">yes</span></div><div class=\"line\">rdbcompression <span class=\"literal\">yes</span></div><div class=\"line\">rdbchecksum <span class=\"literal\">no</span></div><div class=\"line\">dbfilename dump_6315.rdb</div><div class=\"line\">dir ./run/data</div><div class=\"line\"><span class=\"comment\">################################# REPLICATION #################################</span></div><div class=\"line\">slaveof <span class=\"number\">192.168</span><span class=\"number\">.0</span><span class=\"number\">.12</span> <span class=\"number\">6301</span></div><div class=\"line\">slave-serve-stale-data <span class=\"literal\">yes</span></div><div class=\"line\">slave-read-only <span class=\"literal\">yes</span></div><div class=\"line\">repl-diskless-sync <span class=\"literal\">no</span></div><div class=\"line\">repl-diskless-sync-delay <span class=\"number\">5</span></div><div class=\"line\"><span class=\"comment\"># repl-ping-slave-period 10</span></div><div class=\"line\"><span class=\"comment\"># repl-timeout 60</span></div><div class=\"line\">repl-disable-tcp-nodelay <span class=\"literal\">no</span></div><div class=\"line\"><span class=\"comment\"># repl-backlog-size 1mb</span></div><div class=\"line\"><span class=\"comment\"># repl-backlog-ttl 3600</span></div><div class=\"line\">slave-priority <span class=\"number\">80</span></div><div class=\"line\"><span class=\"comment\"># min-slaves-to-write 3</span></div><div class=\"line\"><span class=\"comment\"># min-slaves-max-lag 10</span></div><div class=\"line\"><span class=\"comment\">################################## SECURITY ###################################</span></div><div class=\"line\"><span class=\"comment\"># rename-command CONFIG \"\"</span></div><div class=\"line\"><span class=\"comment\">################################### LIMITS ####################################</span></div><div class=\"line\"><span class=\"comment\"># maxclients 10000</span></div><div class=\"line\"><span class=\"comment\"># maxmemory <bytes></span></div><div class=\"line\"><span class=\"comment\"># maxmemory-policy noeviction</span></div><div class=\"line\"><span class=\"comment\"># maxmemory-samples 5</span></div><div class=\"line\"><span class=\"comment\">############################## APPEND ONLY MODE ###############################</span></div><div class=\"line\">appendonly <span class=\"literal\">no</span></div><div class=\"line\">appendfilename <span class=\"string\">\"appendonly_6315.aof\"</span></div><div class=\"line\">appendfsync <span class=\"literal\">no</span></div><div class=\"line\"><span class=\"literal\">no</span>-appendfsync-on-rewrite <span class=\"literal\">no</span></div><div class=\"line\">auto-aof-rewrite-percentage <span class=\"number\">100</span></div><div class=\"line\">auto-aof-rewrite-min-size <span class=\"number\">64</span>mb</div><div class=\"line\">aof-load-truncated <span class=\"literal\">yes</span></div><div class=\"line\"><span class=\"comment\">################################ LUA SCRIPTING ###############################</span></div><div class=\"line\">lua-time-limit <span class=\"number\">5000</span></div><div class=\"line\"><span class=\"comment\">################################ REDIS CLUSTER ###############################</span></div><div class=\"line\"><span class=\"comment\"># cluster-enabled yes</span></div><div class=\"line\"><span class=\"comment\"># cluster-config-file nodes-6379.conf</span></div><div class=\"line\"><span class=\"comment\"># cluster-node-timeout 15000</span></div><div class=\"line\"><span class=\"comment\"># cluster-slave-validity-factor 10</span></div><div class=\"line\"><span class=\"comment\"># cluster-migration-barrier 1</span></div><div class=\"line\"><span class=\"comment\"># cluster-require-full-coverage yes</span></div><div class=\"line\"><span class=\"comment\">################################## SLOW LOG ###################################</span></div><div class=\"line\">slowlog-log-slower-than <span class=\"number\">10000</span></div><div class=\"line\">slowlog-max-len <span class=\"number\">128</span></div><div class=\"line\"><span class=\"comment\">################################ LATENCY MONITOR ##############################</span></div><div class=\"line\">latency-monitor-threshold <span class=\"number\">0</span></div><div class=\"line\"><span class=\"comment\">############################# EVENT NOTIFICATION ##############################</span></div><div class=\"line\">notify-keyspace-events <span class=\"string\">\"\"</span></div><div class=\"line\"><span class=\"comment\">############################### ADVANCED CONFIG ###############################</span></div><div class=\"line\">hash-max-ziplist-entries <span class=\"number\">512</span></div><div class=\"line\">hash-max-ziplist-value <span class=\"number\">64</span></div><div class=\"line\">list-max-ziplist-entries <span class=\"number\">512</span></div><div class=\"line\">list-max-ziplist-value <span class=\"number\">64</span></div><div class=\"line\">set-max-intset-entries <span class=\"number\">512</span></div><div class=\"line\">zset-max-ziplist-entries <span class=\"number\">128</span></div><div class=\"line\">zset-max-ziplist-value <span class=\"number\">64</span></div><div class=\"line\">hll-sparse-max-bytes <span class=\"number\">3000</span></div><div class=\"line\">activerehashing <span class=\"literal\">yes</span></div><div class=\"line\">client-output-buffer-limit normal <span class=\"number\">0</span> <span class=\"number\">0</span> <span class=\"number\">0</span></div><div class=\"line\">client-output-buffer-limit slave <span class=\"number\">256</span>mb <span class=\"number\">64</span>mb <span class=\"number\">60</span></div><div class=\"line\">client-output-buffer-limit pubsub <span class=\"number\">32</span>mb <span class=\"number\">8</span>mb <span class=\"number\">60</span></div><div class=\"line\">hz <span class=\"number\">10</span></div><div class=\"line\">aof-rewrite-incremental-fsync <span class=\"literal\">yes</span></div><div class=\"line\"><span class=\"number\">3</span>、从节点slave2的配置文件redis_slave_6316.config:</div><div class=\"line\">与上面slave1配置文件需要修改的地方</div><div class=\"line\">pidfile ./run/redis_slaver1_6316.pid</div><div class=\"line\">port <span class=\"number\">6316</span></div><div class=\"line\">logfile <span class=\"string\">\"./run/logs/log_slaver1_6316.log\"</span></div><div class=\"line\">dbfilename dump_6316.rdb</div><div class=\"line\">appendfilename <span class=\"string\">\"appendonly_6316.aof\"</span></div><div class=\"line\"><span class=\"number\">4</span>、从节点slave3的配置文件redis_slave_6317.config:</div><div class=\"line\">与上面slave1配置文件需要修改的地方</div><div class=\"line\">pidfile ./run/redis_slaver1_6317.pid</div><div class=\"line\">port <span class=\"number\">6317</span></div><div class=\"line\">logfile <span class=\"string\">\"./run/logs/log_slaver1_6317.log\"</span></div><div class=\"line\">dbfilename dump_6317.rdb</div><div class=\"line\">appendfilename <span class=\"string\">\"appendonly_6317.aof\"</span></div><div class=\"line\"><span class=\"number\">5</span>、哨兵sentinel1的配置文件sentinel_26301.config:</div><div class=\"line\"><span class=\"comment\"># Example sentinel.conf</span></div><div class=\"line\">port <span class=\"number\">26301</span></div><div class=\"line\"><span class=\"comment\"># sentinel announce-ip 1.2.3.4</span></div><div class=\"line\">dir ./run/tmp</div><div class=\"line\">sentinel monitor master1 <span class=\"number\">192.168</span><span class=\"number\">.0</span><span class=\"number\">.12</span> <span class=\"number\">6301</span> <span class=\"number\">2</span></div><div class=\"line\"><span class=\"comment\"># sentinel auth-pass mymaster MySUPER--secret-0123passw0rd</span></div><div class=\"line\"><span class=\"comment\"># sentinel down-after-milliseconds <master-name> <milliseconds></span></div><div class=\"line\">sentinel down-after-milliseconds master1 <span class=\"number\">30000</span></div><div class=\"line\">sentinel parallel-syncs master1 <span class=\"number\">1</span></div><div class=\"line\">sentinel failover-timeout master1 <span class=\"number\">180000</span></div><div class=\"line\"><span class=\"comment\"># sentinel notification-script mymaster /var/redis/notify.sh</span></div><div class=\"line\"><span class=\"comment\"># sentinel client-reconfig-script mymaster /var/redis/reconfig.sh</span></div><div class=\"line\"><span class=\"comment\"># sentinel can-failover master1 yes</span></div><div class=\"line\">logfile <span class=\"string\">\"/redis-3.0.0/run/logs/sentinellog_m1_26301.log\"</span></div><div class=\"line\"><span class=\"number\">6</span>、哨兵sentinel2的配置文件sentinel_26302.config:</div><div class=\"line\"><span class=\"comment\"># Example sentinel.conf</span></div><div class=\"line\">port <span class=\"number\">26302</span></div><div class=\"line\"><span class=\"comment\"># sentinel announce-ip 1.2.3.4</span></div><div class=\"line\">dir ./run/tmp</div><div class=\"line\">sentinel monitor master1 <span class=\"number\">192.168</span><span class=\"number\">.0</span><span class=\"number\">.12</span> <span class=\"number\">6301</span> <span class=\"number\">2</span></div><div class=\"line\"><span class=\"comment\"># sentinel auth-pass mymaster MySUPER--secret-0123passw0rd</span></div><div class=\"line\"><span class=\"comment\"># sentinel down-after-milliseconds <master-name> <milliseconds></span></div><div class=\"line\">sentinel down-after-milliseconds master1 <span class=\"number\">30000</span></div><div class=\"line\">sentinel parallel-syncs master1 <span class=\"number\">1</span></div><div class=\"line\">sentinel failover-timeout master1 <span class=\"number\">180000</span></div><div class=\"line\"><span class=\"comment\"># sentinel notification-script mymaster /var/redis/notify.sh</span></div><div class=\"line\"><span class=\"comment\"># sentinel client-reconfig-script mymaster /var/redis/reconfig.sh</span></div><div class=\"line\"><span class=\"comment\"># sentinel can-failover master1 yes</span></div><div class=\"line\">logfile <span class=\"string\">\"/redis-3.0.0/run/logs/sentinellog_m1_26302.log\"</span></div><div class=\"line\"><span class=\"number\">7</span>、哨兵sentinel3的配置文件sentinel_26303.config:</div><div class=\"line\"><span class=\"comment\"># Example sentinel.conf</span></div><div class=\"line\">port <span class=\"number\">26303</span></div><div class=\"line\"><span class=\"comment\"># sentinel announce-ip 1.2.3.4</span></div><div class=\"line\">dir ./run/tmp</div><div class=\"line\">sentinel monitor master1 <span class=\"number\">192.168</span><span class=\"number\">.0</span><span class=\"number\">.12</span> <span class=\"number\">6301</span> <span class=\"number\">2</span></div><div class=\"line\"><span class=\"comment\"># sentinel auth-pass mymaster MySUPER--secret-0123passw0rd</span></div><div class=\"line\"><span class=\"comment\"># sentinel down-after-milliseconds <master-name> <milliseconds></span></div><div class=\"line\">sentinel down-after-milliseconds master1 <span class=\"number\">30000</span></div><div class=\"line\">sentinel parallel-syncs master1 <span class=\"number\">1</span></div><div class=\"line\">sentinel failover-timeout master1 <span class=\"number\">180000</span></div><div class=\"line\"><span class=\"comment\"># sentinel notification-script mymaster /var/redis/notify.sh</span></div><div class=\"line\"><span class=\"comment\"># sentinel client-reconfig-script mymaster /var/redis/reconfig.sh</span></div><div class=\"line\"><span class=\"comment\"># sentinel can-failover master1 yes</span></div><div class=\"line\">logfile <span class=\"string\">\"/redis-3.0.0/run/logs/sentinellog_m1_26303.log\"</span></div><div class=\"line\">```` </div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\"># 启动redis和哨兵服务</span></div><div class=\"line\">```yaml</div><div class=\"line\">注意:第一次要先启动redis主服务、从服务,然后才能启动哨兵服务</div><div class=\"line\"><span class=\"number\">1</span>、进入redis安装目录的根目录</div><div class=\"line\"><span class=\"number\">2</span>、启动redis主节点</div><div class=\"line\">[root@localhost redis<span class=\"bullet\">-3.0</span><span class=\"number\">.0</span>]<span class=\"comment\"># redis-server redis_master_6301.config &</span></div><div class=\"line\"><span class=\"number\">3</span>、启动redis从节点</div><div class=\"line\">[root@localhost redis<span class=\"bullet\">-3.0</span><span class=\"number\">.0</span>]<span class=\"comment\"># redis-server redis_slave_6315.config &</span></div><div class=\"line\">[root@localhost redis<span class=\"bullet\">-3.0</span><span class=\"number\">.0</span>]<span class=\"comment\"># redis-server redis_slave_6316.config &</span></div><div class=\"line\">[root@localhost redis<span class=\"bullet\">-3.0</span><span class=\"number\">.0</span>]<span class=\"comment\"># redis-server redis_slave_6317.config &</span></div><div class=\"line\"><span class=\"number\">4</span>、启动哨兵</div><div class=\"line\">[root@localhost redis<span class=\"bullet\">-3.0</span><span class=\"number\">.0</span>]<span class=\"comment\"># redis-sentinel sentinel_26301.config &</span></div><div class=\"line\">[root@localhost redis<span class=\"bullet\">-3.0</span><span class=\"number\">.0</span>]<span class=\"comment\"># redis-sentinel sentinel_26302.config &</span></div><div class=\"line\">[root@localhost redis<span class=\"bullet\">-3.0</span><span class=\"number\">.0</span>]<span class=\"comment\"># redis-sentinel sentinel_26303.config &</span></div><div class=\"line\"></div><div class=\"line\">到目前为止整个redis+sentinel的安装搭建环境就算完成</div><div class=\"line\">`</div></pre></td></tr></table></figure>\n<h1 id=\"常用命名\"><a href=\"#常用命名\" class=\"headerlink\" title=\"常用命名\"></a>常用命名</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div></pre></td><td class=\"code\"><pre><div class=\"line\">进入redis的安装目录</div><div class=\"line\">启动redis-server:</div><div class=\"line\">./redis-server redis_6305.conf &</div><div class=\"line\">启动redis-sentinel </div><div class=\"line\">./redis-sentinel sentinel_6301.config</div><div class=\"line\">./redis-server sentinel_6316.conf --sentinel &</div><div class=\"line\">查看某个端口信息:</div><div class=\"line\">./redis-cli -p <span class=\"number\">6301</span> info</div><div class=\"line\">./redis-cli -p <span class=\"number\">6301</span> info Replication</div><div class=\"line\">./redis-cli -p <span class=\"number\">6301</span> info Sentinel</div><div class=\"line\">查看某个主机上的信息redis信息</div><div class=\"line\">./redis-cli -h <span class=\"number\">10.16</span><span class=\"number\">.41</span><span class=\"number\">.52</span> -p <span class=\"number\">6316</span> info</div><div class=\"line\">./redis-cli -h <span class=\"number\">10.16</span><span class=\"number\">.41</span><span class=\"number\">.52</span> -p <span class=\"number\">6316</span> info Replication</div><div class=\"line\">./redis-cli -h <span class=\"number\">10.16</span><span class=\"number\">.41</span><span class=\"number\">.52</span> -p <span class=\"number\">6316</span> info Sentinel</div><div class=\"line\">关闭本机redis服务</div><div class=\"line\">./redis-cli -p <span class=\"number\">6379</span> shutdown</div><div class=\"line\">关闭远程主机redis服务</div><div class=\"line\">./redis-cli -h <span class=\"number\">192.168</span><span class=\"number\">.9</span><span class=\"number\">.18</span> -p <span class=\"number\">6379</span> shutdown</div><div class=\"line\">客户端连接本机</div><div class=\"line\">./redis-cli -p <span class=\"number\">6301</span></div><div class=\"line\">客户端连接远程机</div><div class=\"line\">./redis-cli -h <span class=\"number\">10.16</span><span class=\"number\">.41</span><span class=\"number\">.53</span> -p <span class=\"number\">6301</span></div><div class=\"line\">切换连接</div><div class=\"line\">ssh app@<span class=\"number\">10.16</span><span class=\"number\">.41</span><span class=\"number\">.52</span></div><div class=\"line\"></div><div class=\"line\">使用命令关闭RDB持久化</div><div class=\"line\">`</div></pre></td></tr></table></figure>\n"},{"title":"logback 日志配置","url":"https://yangzhiw.github.io/2016/07/21/logback/","content":"<h1 id=\"写入文件配置\"><a href=\"#写入文件配置\" class=\"headerlink\" title=\"写入文件配置\"></a>写入文件配置</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><appender name=<span class=\"string\">\"FILE\"</span> class=<span class=\"string\">\"ch.qos.logback.core.rolling.RollingFileAppender\"</span><span class=\"string\">></span></div><div class=\"line\"> <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\"></div><div class=\"line\"> <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern></div><div class=\"line\"> <maxHistory>90</maxHistory></div><div class=\"line\"> </rollingPolicy></div><div class=\"line\"> <encoder></div><div class=\"line\"> <charset>utf-8</charset></div><div class=\"line\"> <Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern></div><div class=\"line\"> </encoder></div><div class=\"line\"></appender></div></pre></td></tr></table></figure>\n<h1 id=\"写入mysql数据库配置\"><a href=\"#写入mysql数据库配置\" class=\"headerlink\" title=\"写入mysql数据库配置\"></a>写入mysql数据库配置</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><appender name=<span class=\"string\">\"DB\"</span> class=<span class=\"string\">\"ch.qos.logback.classic.db.DBAppender\"</span><span class=\"string\">></span></div><div class=\"line\"> <!--日志异步到数据库 --></div><div class=\"line\"> <connectionSource class=\"ch.qos.logback.core.db.DataSourceConnectionSource\"></div><div class=\"line\"> <!--连接池 --></div><div class=\"line\"> <dataSource class=\"org.springframework.jdbc.datasource.DriverManagerDataSource\"></div><div class=\"line\"> <driverClassName>com.mysql.jdbc.Driver</driverClassName></div><div class=\"line\"> <url>jdbc:mysql://localhost:3306/DB</url></div><div class=\"line\"> <username >root</username></div><div class=\"line\"> <password>root</password></div><div class=\"line\"> </dataSource></div><div class=\"line\"> </connectionSource></div><div class=\"line\"> </appender></div></pre></td></tr></table></figure>\n<h1 id=\"写入控制台配置\"><a href=\"#写入控制台配置\" class=\"headerlink\" title=\"写入控制台配置\"></a>写入控制台配置</h1><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><appender name=<span class=\"string\">\"STDOUT\"</span> class=<span class=\"string\">\"ch.qos.logback.core.ConsoleAppender\"</span><span class=\"string\">></span></div><div class=\"line\"> <!-- 日志输出编码 --> </div><div class=\"line\"> <Encoding>UTF-8</Encoding> </div><div class=\"line\"> <layout class=\"ch.qos.logback.classic.PatternLayout\"> </div><div class=\"line\"> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> </div><div class=\"line\"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n </div><div class=\"line\"> </pattern> </div><div class=\"line\"> </layout> </div><div class=\"line\"> </appender></div></pre></td></tr></table></figure>\n<h1 id=\"异步写入\"><a href=\"#异步写入\" class=\"headerlink\" title=\"异步写入\"></a>异步写入</h1><pre><code class=\"yaml\"><appender name=<span class=\"string\">\"ASYNC\"</span> class=<span class=\"string\">\"ch.qos.logback.classic.AsyncAppender\"</span><span class=\"string\">>\n <queueSize>512</queueSize>\n <appender-ref ref=\"FILE\"/>\n</appender></span>\n</code></pre>\n"},{"title":"Hello World","url":"https://yangzhiw.github.io/2016/07/21/hello-world/","content":"<p>Welcome to <a href=\"https://hexo.io/\" target=\"_blank\" rel=\"external\">Hexo</a>! This is your very first post. Check <a href=\"https://hexo.io/docs/\" target=\"_blank\" rel=\"external\">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href=\"https://hexo.io/docs/troubleshooting.html\" target=\"_blank\" rel=\"external\">troubleshooting</a> or you can ask me on <a href=\"https://github.com/hexojs/hexo/issues\" target=\"_blank\" rel=\"external\">GitHub</a>.</p>\n<h2 id=\"Quick-Start\"><a href=\"#Quick-Start\" class=\"headerlink\" title=\"Quick Start\"></a>Quick Start</h2><h3 id=\"Create-a-new-post\"><a href=\"#Create-a-new-post\" class=\"headerlink\" title=\"Create a new post\"></a>Create a new post</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo new <span class=\"string\">\"My New Post\"</span></div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/writing.html\" target=\"_blank\" rel=\"external\">Writing</a></p>\n<h3 id=\"Run-server\"><a href=\"#Run-server\" class=\"headerlink\" title=\"Run server\"></a>Run server</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo server</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/server.html\" target=\"_blank\" rel=\"external\">Server</a></p>\n<h3 id=\"Generate-static-files\"><a href=\"#Generate-static-files\" class=\"headerlink\" title=\"Generate static files\"></a>Generate static files</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo generate</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/generating.html\" target=\"_blank\" rel=\"external\">Generating</a></p>\n<h3 id=\"Deploy-to-remote-sites\"><a href=\"#Deploy-to-remote-sites\" class=\"headerlink\" title=\"Deploy to remote sites\"></a>Deploy to remote sites</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo deploy</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/deployment.html\" target=\"_blank\" rel=\"external\">Deployment</a></p>\n"},{"title":"","url":"https://yangzhiw.github.io/about/index.html","content":"<h1 id=\"博客介绍\"><a href=\"#博客介绍\" class=\"headerlink\" title=\"博客介绍\"></a>博客介绍</h1><blockquote>\n<p>博客大部分都是来自对工作中遇到的问题和学习新技术的一些笔记</p>\n</blockquote>\n<h1 id=\"本人介绍\"><a href=\"#本人介绍\" class=\"headerlink\" title=\"本人介绍\"></a>本人介绍</h1><blockquote>\n<p>本人现工作于浙江杭州</p>\n</blockquote>\n"},{"title":"search","url":"https://yangzhiw.github.io/search/index.html","content":""}]