Disruptor

Disruptor http://www.cnblogs.com/killmyday/archive/2012/12/02/2798218.html http://www.cnblogs.com/haiq/p/4112689.html 票池暂定使用disruptor来做消息队列,把最近对disruptor的调研结果整理一下。大部分文字都是把disruptor和其它网站上看到的资料翻译一下。 原文: http://www.oraclejavamagazine-digital.com/javamagazine/20120304/?pg=56&pm=1&u1=friend#pg56 Disruptor是什么? Disruptor是一个线程间通信的框架,即在多线程间共享数据。它是由LMAX公司开发的可信消息传递架构的一部分,以便用非常快速的方法来在多组件之间传递数据。它的一个核心思想是理解并适应硬件工作方式来达到最优的效果。 在很多 (并行) 架构里,普遍使用队列来共享数据 (例如传递消息) 。图1就是使用队列来传递消息的一个示意图 (里面蓝色的小圈圈表示一个线程) 。这种架构允许生产线程 (图1里的stage1) 在消费线程 (图1里的stage2) 处理不过来的情况下,还可以继续后面的工作,队列在其中用来做为消息的缓冲区。 图1 在最简单的情况下,disruptor可以用来替代图1架构里的队列,也就是线程间通过disruptor来传递数据。在disruptor里保存消息的数据结构是环状缓冲区 (RingBuffer - 后面都用RingBuffer这个术语) 。生产线程stage1将消息放到 RingBuffer 里,然后消费线程stage2从 RingBuffer里读取消息,如图2。 图2 从图2里可以看到,RingBuffer 里的每一个元素都有一个序列号 (sequence number) 来索引,RingBuffer维护当前最新放置的元素的序列号,这个序列号一直递增, (通过求余来得到元素在RingBuffer下面的数组下标) 。 Disruptor的关键特性是无锁编程,这个是通过单一写线程的方式实现的 - 即一块数据永远只有一个线程写入。通过遵循这个编程原则来避免使用昂贵的同步锁或CAS操作,这就是为什么Disruptor这么快的原因。 因为RingBuffer规避了锁,而且每个EventProcessor维护自己的序列号。 向Disruptor发布消息 往RingBuffer里写入消息使用两步提交的方式。首先,生产线程Stage1需要确定RingBuffer里下一个空闲槽,如图3。 图3 RingBuffer维护了最后一次写入的序列号 (图3里的18号) ,因此就可以推知下一个空闲的槽号。RingBuffer通过检查所有从RingBuffer读取消息的EventProcessor的序列号,以判别下一个槽号是否空闲。 图4演示了索取下一个空闲槽序列号的过程。 图4 当生产线程拿到了下一个序利号之后,它从RingBuffer里拿到槽里保存的对象并执行任何操作。这个过程中,因为RingBuffer的最新序列号依然是18,因此其它线程无法读取19号槽里面的事件 - 生产线程还在处理它。 图5 图5演示了RingBuffer在提交变更后的情况。当生产线程处理完第19号槽的数据后,它告诉RingBuffer将其公布出来。这个时候,RingBuffer才会更新它维护的序列号,任何等待读取第19号槽里的数据的线程才能读取它。 从RingBuffer里读取信息 Disruptor框架里提供了一个叫做BatchEventProcessor来从RingBuffer里读取数据。当生产线程向RingBuffer要求下一个可写入的空闲槽的序列号时,同时一个EventProcessor (类似消费者,但其并消费RingBuffer里的元素 - 即不从RingBuffer里移除任何元素) 也会维护其最后所处理的数据的序列号,并要求下一个可处理的数据的序列号。 图6演示了EventProcessor等待处理下一个可读取数据序利号的过程。 图6 EventProcessor不是直接从RingBuffer里获取下一个可读取数据的序列号,而是通过一个SequenceBarrier对象来做的,稍后我们谈这个细节。 图6里,EventProcessor (即消费者线程Stage2) 最后看到的是第16号槽的数据,它希望处理下一个 (第17号) 槽的数据,因此它执行SequenceBarrier的waitFor(17)函数调用。线程Stage2可以一直等待下一个可读序列号,因为如果尚没有数据生产出来的话,它什么也不需要做。但跟图6所示的一样,RingBuffer里最新可用数据已经到18号槽了,因此waitFor返回18,即告诉EventProcessor可以一直读到第18号的所有数据。如图7。 图7 这种模式提供了很好的批处理行为,可以使用这种批处理代码来实现EventHandler,在Disruptor里性能测试FizzBuzzEventHandler就是一个很好的例子。 处理系统组件之间的依赖关系 Disruptor处理系统内部多组件的依赖关系,而不引入任何线程竞争的做法很有意思。Disruptor遵循的是单线程写入,多线程读取的做法。Disruptor的原始设计是支持几步具有特定顺序的串行流水线操作 - 这种操作在企业级的系统里很常见。图8演了一个标准的三步流水线操作: ...

2015-08-28 · 1 min · 107 words · -

进程间通信IPC、LPC、RPC

进程间通信IPC、LPC、RPC 进程间通信 IPC、LPC、RPC http://www.cnblogs.com/gsk99/archive/2010/12/13/1904541.html 进程间通信 (IPC,Inter-Process Communication) , 指至少两个进程或线程间传送数据或信号的一些技术或方法。进程是计算机系统分配资源的最小单位。每个进程都有自己的一部分独立的系统资源,彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作,才有了进程间通信。这些进程可以运行在同一计算机上或网络连接的不同计算机上。 进程间通信技术包括消息传递、同步、共享内存和远程过程调用。 IPC是一种标准的Unix通信机制。 有两种类型的进程间通信(IPC)。 本地过程调用(LPC)LPC用在多任务操作系统中,使得同时运行的任务能互相会话。这些任务共享内存空间使任务同步和互相发送信息。 远程过程调用(RPC)RPC类似于LPC,只是在网上工作。RPC开始是出现在Sun微系统公司和HP公司的运行UNIX操作系统的计算机中。 通过IPC和RPC,程序能利用其它程序或计算机处理的进程。客户机/服务器模式计算把远程过程调用与其它技术如消息传递一道,作为系统间通信的一种机制。客户机执行自己的任务,但靠服务器提供后端文件服务。RPC为客户机提供向后端服务器申请服务的通信机制。如果你把客户机/服务器应用程序想作是一个分离的程序,服务器能运行数据访问部分,因为它离数据最近,客户机能运行数据表 示和与用户交互的前端部分。这样,远程过程调用可看作是把分割的程序通过网络重组的部件。LPC有时也称耦合(Coupling)机制。 用这种方式分割程序,当用户要访问数据时就无需每次拷贝整个数据库或它的大部分程序到用户系统。其实,服务器只处理请求,甚至只执行一些数据计算,把得出的结果再发送给用户。因为当数据存放在一个地方时,数据库同步很容易实现,所以多个用户可同时访问相同的数据。 RPC: Remote procedure call (RPC) is an Inter-process communication technology that allows a computer program to cause a subroutine or procedure to execute in another address space (commonly on another computer on a shared network) without the programmer explicitly coding the details for this remote interaction. IPC: Inter-process communication (IPC) is a set of techniques for the exchange of data among multiple threads in one or more processes. Processes may be running on one or more computers connected by a network. ...

2015-08-28 · 1 min · 108 words · -

who

Linux 查看用户, 当前登录用户, 登录日志 # 查看 ssh 上已经连接的用户、session # 查看登录用户正在使用的进程信息 w who who -a netstat -tnpa | grep ‘ESTABLISHED.*sshd’ ps auxwww | grep sshd: ps ax | grep sshd /etc/shadow 和 /etc/passwd 系统存在的所有用户名 more /var/log/secure who /var/log/wtmp 干了些什么? root账户下输入su - username 切换到username下输入 history 能看到这个用户历史命令,默认最近的1000条 http://blog.csdn.net/wudiyi815/article/details/8061459 作为系统管理员,你可能经常会 (在某个时候) 需要查看系统中有哪些用户正在活动。有些时候,你甚至需要知道他 (她) 们正在做什么。本文为我们总结了4种查看系统用户信息 (通过编号 (ID) ) 的方法。 w w命令用于显示已经登录系统的用户的名称,以及他们正在做的事。该命令所使用的信息来源于/var/run/utmp文件。w命令输出的信息包括: USER 用户名称 tty 用户的机器名称或tty号 FROM 远程主机地址 LOGIN@ 用户登录系统的时间 IDLE 空闲时间, 时间格式: 22:29m(22h29m), 46.00s, 27:47(27m47s) JCPU 附加到 tty (终端) 的进程所用的时间 PCPU 当前进程所用时间 WHAT 用户当前正在使用的命令 IDLE The idle time is supposed to tell how long it has been since the user typed any input on that terminal. For Xwindows sessions, it is broken since Xwindows never reads input from a terminal, but instead gathers input directly from your mouse and keyboard, so the terminal never gets its timestamp updated since it is never read from. ...

2015-08-27 · 2 min · 281 words · -

Java Unix Socket

Java Unix Socket http://www.oschina.net/p/juds/similar_projects?lang=0&sort=view Java Unix Domain Sockets (JUDS) 提供了 Java 的方法用来访问 Unix domain sockets socket 。 示例代码: package com.google.code.juds.test; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import com.google.code.juds.*; public class TestUnixDomainSocket { public static void main(String[] args) throws IOException { if (args.length != 1) { System.out .println("usage: java TestUnixDomainSocket socketfilename"); System.exit(1); } String socketFile = args[0]; byte[] b = new byte[128]; // Testcase 1.1: Test UnixDomainSocketClient with a stream socket UnixDomainSocketClient socket = new UnixDomainSocketClient(socketFile, UnixDomainSocket.SOCK_STREAM); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); in.read(b); System.out.println("Text received: \"" + new String(b) + "\""); String text = "[2] Hello! I'm the client!"; out.write(text.getBytes()); System.out.println("Text sent: " + "\"" + text + "\""); socket.close(); // Testcase 1.2: Test UnixDomainSocketClient with a datagram socket socket = new UnixDomainSocketClient(socketFile, UnixDomainSocket.SOCK_DGRAM); System.out.println("Provoke and catch an " + "UnsupportedOperationException:"); try { in = socket.getInputStream(); } catch (UnsupportedOperationException e) { System.out.println("UnsupportedOperationException has been " + "thrown as expected."); } out = socket.getOutputStream(); text = "[3] Hello! I'm the client!"; out.write(text.getBytes()); System.out.println("Text sent: \"" + text + "\""); socket.close(); // Testcase 2.1: Test UnixDomainSocketServer with a stream socket System.out.println("\nTest #2: Test UnixDomainSocketServer\nTestcase " + "2.1: Test UnixDomainSocketServer with a stream socket..."); UnixDomainSocketServer ssocket = new UnixDomainSocketServer(socketFile, UnixDomainSocket.SOCK_STREAM); in = ssocket.getInputStream(); out = ssocket.getOutputStream(); in.read(b); System.out.println("Text received: \"" + new String(b) + "\""); text = "[5] Hello! I'm the server!"; out.write(text.getBytes()); System.out.println("Text sent: " + "\"" + text + "\""); ssocket.close(); ssocket.unlink(); // Testcase 2.2: Test UnixDomainSocketServer with a datagram socket System.out.println("Testcase 2.2: Test UnixDomainSocketServer with " + "a datagram socket..."); ssocket = new UnixDomainSocketServer(socketFile, UnixDomainSocket.SOCK_DGRAM); System.out.println("Provoke and catch an " + "UnsupportedOperationException:"); in = ssocket.getInputStream(); try { out = ssocket.getOutputStream(); } catch (UnsupportedOperationException e) { System.out.println("UnsupportedOperationException has been " + "thrown as expected."); } in.read(b); System.out.println("Text received: \"" + new String(b) + "\""); ssocket.close(); ssocket.unlink(); } }

2015-08-26 · 2 min · 299 words · -

unix domain socket, UDS

unix domain socket, UDS ss -nxp ss -nxlp http://blog.csdn.net/bingqingsuimeng/article/details/8470029 http://blog.chinaunix.net/uid-20511624-id-1659107.html 什么是Socket Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程式员能够用他们来研发TCP/IP网络上的应用程式。要学Internet上的TCP/IP网络编程,必须理解Socket接口。 Socket接口设计者最先是将接口放在Unix操作系统里面的。假如了解 Unix 系统的输入和输出的话,就很容易了解 Socket 了。网络的 Socket数据传输是一种特别的I/O,Socket也是一种文档描述符。Socket也具备一个类似于打开文档的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种: 流式Socket (SOCK_STREAM) 和数据报式Socket (SOCK_DGRAM) 。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 Socket 建立 为了建立Socket,程式能够调用Socket函数,该函数返回一个类似于文档描述符的句柄。socket函数原型为: int socket(int domain, int type, int protocol); domain指明所使用的协议族,通常为PF_INET,表示互连网协议族 (TCP/IP协议族) ;type参数指定socket的类型: SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket (SOCK_RAW) ,允许程式使用低层协议;protocol通常赋值"0"。 Socket()调用返回一个整型socket描述符,您能够在后面的调用使用他。 Socket描述符是个指向内部数据结构的指针,他指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。Socket执行体为您管理描述符表。 两个网络程式之间的一个网络连接包括五种信息: 通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。 Socket配置 通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端连同面向连接socket的服务端通过调用 bind函数来配置本地信息。 Bind函数将socket和本机上的一个端口相关联,随后您就能够在该端口监听服务请求。Bind函数原型为: int bind(int sockfd,struct sockaddr *my_addr, int addrlen); Sockfd是调用socket函数返回的socket描述符,my_addr是个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被配置为sizeof(struct sockaddr)。 struct sockaddr结构类型是用来保存socket信息的: struct sockaddr { unsigned short sa_family; /地址族, AF_xxx/ char sa_data[14]; /14 字节的协议地址/ ...

2015-08-26 · 6 min · 1223 words · -

java UDP

java UDP 一. UDP协议定义 UDP协议的全称是用户数据报,在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。 二. 使用UDP的原因 它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和OICQ就是使用的UDP协议。在选择使用协议的时候,选择UDP必须要谨慎。在网络质量令人不十分满意的环境下,UDP协议数据包丢失会比较严重。 三. 在Java中使用UDP协议编程的相关类 InetAddress 用于描述和包装一个Internet IP地址。有如下方法返回实例: getLocalhost(): 返回封装本地地址的实例。 getAllByName(String host): 返回封装Host地址的InetAddress实例数组。 getByName(String host): 返回一个封装Host地址的实例。其中,Host可以是域名或者是一个合法的IP地址。 InetAddress.getByAddress(addr): 根据地址串返回InetAddress实例。 InetAddress.getByAddress(host, addr): 根据主机地符串和地址串返回InetAddress实例。 DatagramSocket 用于接收和发送UDP的Socket实例。该类有3个构造函数: DatagramSocket(): 通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。程序会让操作系统分配一个可用的端口。 DatagramSocket(int port): 创建实例,并固定监听Port端口的报文。通常用于服务端 DatagramSocket(int port, InetAddress localAddr): 这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文。 DatagramSocket具有的主要方法如下: receive(DatagramPacket d): 接收数据报文到d中。receive方法产生一个"阻塞"。“阻塞"是一个专业名词,它会产生一个内部循环,使程序暂停在这个地方,直到一个条件触发。 send(DatagramPacket dp): 发送报文dp到目的地。 setSoTimeout(int timeout): 设置超时时间,单位为毫秒。 close(): 关闭DatagramSocket。在应用程序退出的时候,通常会主动释放资源,关闭Socket,但是由于异常地退出可能造成资源无法回收。所以,应该在程序完成时,主动使用此方法关闭Socket,或在捕获到异常抛出后关闭Socket。 DatagramPacket 用于处理报文,它将Byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成Byte数组。应用程序在产生数据包是应该注意,TCP/IP规定数据报文大小最多包含65507个,通常主机接收548个字节,但大多数平台能够支持8192字节大小的报文。DatagramPacket类的构建器共有4个: DatagramPacket(byte[] buf, int length): 将数据包中Length长的数据装进Buf数组,一般用来接收客户端发送的数据。 DatagramPacket(byte[] buf, int offset, int length): 将数据包中从Offset开始、Length长的数据装进Buf数组。 DatagramPacket(byte[] buf, int length, InetAddress clientAddress, int clientPort): 从Buf数组中,取出Length长的数据创建数据包对象,目标是clientAddress地址,clientPort端口,通常用来发送数据给客户端。 ...

2015-08-24 · 2 min · 273 words · -

maven Scope

maven Scope maven依赖关系中Scope的作用 Dependency Scope 在POM 4中,中还引入了,它主要管理依赖的部署。目前可以使用5个值: compile,缺省值,适用于所有阶段,会随着项目一起发布。 provided,类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar。 runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。 test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。 system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。

2015-08-24 · 1 min · 12 words · -

Maven jar plugin

Maven jar plugin 1.修改pom.xml增加如下内容 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <manifest> true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>com.sysware.HelloWorld</mainClass> </manifest> </archive> </configuration> </plugin> 运行mvn clean package即可 html …src/main/java src/main/resources ...

2015-08-24 · 1 min · 81 words · -

Java读 环境变量

Java读 环境变量 http://ling091.iteye.com/blog/354052 读取环境变量时可以使用 System.getProperty 或 System.getenv 方法。 System.getProperty 方法 ( JDK1.4 ) 用来读取针对 JVM 的属性,如程序当前的运行路径、路径分隔符、 Java 版本等, ( 见 System.getProperty() 参数大全 ) ,它也可以读取在运行程序时设置的自定义属性。 获取一个JVM已定义属性 //获取系统当前的运行路径 System.out.println(“current path = " + System.getProperty(“user.dir”) ); 输出: current path = E:\program\java\test\Test 获取应用程序的属性: 在命令中输入下面的命令,其中的-D用于设置一个属性 -D= SET myvar=Hello world SET myothervar=nothing java -Dmyvar="%myvar%” -Dmyothervar="%myothervar%" myClass myClass中读取这些属性 String myvar = System.getProperty(“myvar”); String myothervar = System.getProperty(“myothervar”); 如果要读取操作系统的环境变量 (如 Path 、 TEMP 或 TMP 、 JAVA_HOME 等。) 则可以使用 System.getenv 方法,但是由于某些原因,该方法被去掉了,直到 JDK1.5 后,该方法又被加进去 [3] 。 ...

2015-08-14 · 1 min · 119 words · -

java ssh

java ssh http://www.rigongyizu.com/java-ssh-copy-remote-file/ http://www.rigongyizu.com/tag/java/ jsch http://www.jcraft.com/jsch/ http://www.rigongyizu.com/tag/java/ Ganymed SSH-2 for Java http://www.cleondris.ch/opensource/ssh2/ 也是纯java实现了ssh2协议,这个库代码比较老,一直没更新了,只在J2SE 1.4.2 和 5.0上测试过。网上有些例子。 sshj https://github.com/shikhar/sshj API封装的很友好,功能齐全。 sshd http://mina.apache.org/sshd-project/index.html 基于mina,可以同时支持ssh服务端和客户端。

2015-08-14 · 1 min · 22 words · -

Maven

Maven http://juvenshun.iteye.com/blog/376422 什么是版本管理 首先,这里说的版本管理 (version management) 不是指版本控制 (version control) ,但是本文假设你拥有基本的版本控制的知识,了解subversion的基本用法。版本管理中说得版本是指构件 (artifact) 的版本,而非源码的版本 (如subversion中常见的rXXX,或者git中一次提交都有个sha1的commit号) 。 比如我有一个项目,其artifactId为myapp,随着项目的进展,我们会生成这样一些jar: myapp-1.0-SNAPSHOT.jar,myapp-1.0.jar,myapp-1.1-SNAPSHOT.jar,myapp-1.0.1.jar等等。你可能会说,这很简单啊,我在POM中改个version,mvn clean install不就完了?但这只是表面,本文我将讲述,snapshot和release版本的区别,如何自动化版本发布 (如果你的项目有几十个module,你就会觉得手工改POM来升级版本是很痛苦的事情) ,结合自动化发布的过程,这里还会介绍maven-release-plugin。此外,一些scm概念也会被涉及到,比如tag和branch。 前提: 版本控制 不管怎样,我们都需要建立一个项目并提交到SCM中,这里我以subversion为例。你得有一个配置好的subversion repository,这里我建立了一个空的svn仓库,其地址为: https://192.168.1.100:8443/svn/myapp/ 现在,该目录下只有三个空的典型的子目录: /trunk/, branches/, tags/。分别用来存放主干,分支,以及标签。 接着将项目导入到svn仓库中,到项目根目录,运行如下命令: svn import -m 'project initialization' https://192.168.1.100:8443/svn/myapp/trunk (注意,这么做你会将目录下所有文件导入到svn库中,但是这其中某些目录和文件是不应该被导入的,如/target目录,以及eclipse相关的项目文件) 目前,我们将项目的版本设置为1.0-SNAPSHOT。 为什么用SNAPSHOT? 我先说说如果没有SNAPSHOT会是什么样子。假设你的项目有2个模块,A,B,其中A依赖B。这两个模块分别由甲,乙两个个人负责开发。在开发过程中,因为A是依赖于B的,因此乙每次做一个改动都会影响到甲,于是,乙提交了一些更改后,需要让甲看到。这个时候,怎么做呢?乙对甲说,"你签出我的代码,build一下就OK了",甲有点不情愿,但还是照做了,签出代码,svn clean install,然后,发现build出错了,有个测试没有pass。甲郁闷了,对乙说,"你的代码根本不能用,我不想build,你build好了给我",乙看了看确实自己的代码build不过,于是回去解决了,然后打了个jar包,扔给甲,甲对了对groupId,artifactId,放到了自己的.m2/repository/目录下,OK,能用了。 于是乙每次更新都这样做,打包,复制,然后甲粘贴,使用……渐渐的,大家发现这是个很笨的办法,这是纯手工劳动阿,程序员最BS的就是重复劳动。一天,甲对乙说,"你知道nexus么?你把你的jar发布到nexus上就可以了,我要用就自动去下载,这多棒!"乙说"哦?有这好东西,我去看看"于是乙发现了nexus这块新大陆,并成功的发布了B到nexus上。 (见,Nexus入门指南, (图文) ) 。 但是,请注意,我们这里的一切都假设没有SNAPSHOT,因此如果乙不更改版本,甲下载一次如B-1.0.jar之后,maven认为它已经有了正确的B的版本,就不会再重新下载。甲发现了这个问题,对乙说"你的更新我看不到,你更新了么?"乙说"不可能!我看看",于是检查一下甲下载的C-1.0.jar,发现那是几天前的。乙一拍脑袋,说"这简单,我更新一下我的版本就好了,我发布个B-1.1.jar上去,你更新下依赖版本",甲照做了,似乎这么做是可行的。 这里有一个问题,一次提交就更新一个版本,这明显不是正确的管理办法,此外,乙得不停的通知甲更新对B的依赖版本,累不累阿?1.0,或者说1.1,2.0,都代表了稳定,这样随随便便的改版本,能稳定么? 所以Maven有SNAPSHOT版本的概念,它与release版本对应,后者是指1.0,1.1,2.0这样稳定的发布版本。 现在乙可以将B的版本设置成1.0-SNAPSHOT,每次更改后,都mvn deploy到nexus中,每次deploy,maven都会将SNAPSHOT改成一个当前时间的timestamp,比如B-1.0-SNAPSHOT.jar到nexus中后,会成为这个样子: B-1.0-20081017-020325-13.jar。Maven在处理A中对于B的SNAPSHOT依赖时,会根据这样的timestamp下载最新的jar,默认Maven每天 更新一次,如果你想让Maven强制更新,可以使用-U参数,如: mvn clean install -U 。 现在事情简化成了这个样子: 乙做更改,然后mvn deploy,甲用最简单的maven命令就能得到最新的B。 从1.0-SNAPSHOT到1.0到1.1-SNAPSHOT SNAPSHOT是快照的意思,项目到一个阶段后,就需要发布一个正式的版本 (release版本) 。一次正式的发布需要这样一些工作: 在trunk中,更新pom版本从1.0-SNAPSHOT到1.0 对1.0打一个svn tag 针对tag进行mvn deploy,发布正式版本 更新trunk从1.0到1.1-SNAPSHOT 你可以手工一步步的做这些事情,无非就是一些svn操作,一些pom编辑,还有一些mvn操作。但是你应该明白,手工做这些事情,一来繁琐,而来容易出错。因此这里我介绍使用maven插件来自动化这一系列动作。 SCM 首先我们需要在POM中加入scm信息,这样Maven才能够替你完成svn操作,这里我的配置如下: ```xml 需要注意的是,很多windows使用的tortoiseSVN客户端,而没有svn命令行客户端,这会导致Maven所有svn相关的工作失败,因此,你首先确保svn -version能够运行。 分发仓库 想要让Maven帮我们自动发布,首先我们需要配置好分发仓库。关于这一点,见Maven最佳实践: Maven仓库——分发构件至远程仓库。 maven-release-plugin 紧接着,我们需要配置maven-release-plugin,这个插件会帮助我们升级pom版本,提交,打tag,然后再升级版本,再提交,等等。基本配置如下: ```xml <version>2.0-beta-7</version> <configuration> <tagBase>https://192.168.1.100:8443/svn/myapp/tags/</tagBase> </configuration> </plugin> GAV我就不多解释了,这里我们需要注意的是configuration元素下的tagBase元素,它代表了我们svn中的tag目录,也就是说,maven-release-plugin帮我们打tag的时候,其基础目录是什么。这里,我填写了svn仓库中的标准的tags目录。 提交代码 接着,确保你的所有代码都提交了,如果你有未提交代码,release插件会报错,既然你要发布版本了,就表示代码是稳定的,所以要么要么把代码提交了,要么把本地的更改抛弃了。 开始工作 现在,屏住呼吸,执行: mvn release:prepare 执行过程中,你会遇到这样的提示: What is the release version for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) 1.0: : ——"你想将1.0-SNAPSHOT发布为什么版本?默认是1.0。"我要的就是1.0,直接回车。 What is SCM release tag or label for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) myapp-1.0: : ——"发布的tag标签名称是什么?默认为myapp-1.0。"我还是要默认值,直接回车。 What is the new development version for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) 1.1-SNAPSHOT: : ——"主干上新的版本是什么?默认为1.1-SNAPSHOT。"哈,release插件会自动帮我更新版本到1.1-SNAPSHOT,很好,直接回车。 然后屏幕刷阿刷,maven在build我们的项目,并进行了一些svn操作,你可以仔细查看下日志。 那么结果是什么呢?你可以浏览下svn仓库: 我们多了一个tag: https://192.168.1.100:8443/svn/myapp/tags/myapp-1.0/,这就是需要发布的版本1.0。 再看看trunk中的POM,其版本自动升级成了1.1-SNAPSHOT。 这不正是我们想要的么?等等,好像缺了点什么,对了,1.0还没有发布到仓库中呢。 再一次屏住呼吸,执行: mvn release:perform maven-release-plugin会自动帮我们签出刚才打的tag,然后打包,分发到远程Maven仓库中,至此,整个版本的升级,打标签,发布等工作全部完成。我们可以在远程Maven仓库中看到正式发布的1.0版本。 这可是自动化的 ,正式的 版本发布! Maven的版本规则 前面我们提到了SNAPSHOT和Release版本的区别,现在看一下,为什么要有1.0,1.1,1.1.1这样的版本,这里的规则是什么。 Maven主要是这样定义版本规则的: <主版本>.<次版本>.<增量版本> 比如说1.2.3,主版本是1,次版本是2,增量版本是3。 主版本一般来说代表了项目的重大的架构变更,比如说Maven 1和Maven 2,在架构上已经两样了,将来的Maven 3和Maven 2也会有很大的变化。 次版本一般代表了一些功能的增加或变化,但没有架构的变化,比如说Nexus 1.3较之于Nexus 1.2来说,增加了一系列新的或者改进的功能 (仓库镜像支持,改进的仓库管理界面等等) ,但从大的架构上来说,1.3和1.2没什么区别。至于增量版本,一般是一些小的bug fix,不会有重大的功能变化。 一般来说,在我们发布一次重要的版本之后,随之会开发新的版本,比如说,myapp-1.1发布之后,就着手开发myapp-1.2了。由于myapp-1.2有新的主要功能的添加和变化,在发布测试前,它会变得不稳定,而myapp-1.1是一个比较稳定的版本,现在的问题是,我们在myapp-1.1中发现了一些bug (当然在1.2中也存在) ,为了能够在段时间内修复bug并仍然发布稳定的版本,我们就会用到分支 (branch) ,我们基于1.1开启一个分支1.1.1,在这个分支中修复bug,并快速发布。这既保证了版本的稳定,也能够使bug得到快速修复,也不同停止1.2的开发。只是,每次修复分支1.1.1中的bug后,需要merge代码到1.2 (主干) 中。 上面讲的就是我们为什么要用增量版本。 实战分支 目前我们trunk的版本是1.1-SNAPSHOT,其实按照前面解释的版本规则,应该是1.1.0-SNAPSHOT。 现在我们想要发布1.1.0,然后将主干升级为1.2.0-SNAPSHOT,同时开启一个1.1.x的分支,用来修复1.1.0中的bug。 首先,在发布1.1.0之前,我们创建1.1.x分支,运行如下命令: mvn release:branch -DbranchName=1.1.x -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false 这是maven-release-plugin的branch目标,我们指定branch的名称为1.1.x,表示这里会有版本1.1.1, 1.1.2等等。updateBranchVersions=true的意思是在分支中更新版本,而updateWorkingCopyVersions=false是指不更改当前工作目录 (这里是trunk) 的版本。 在运行该命令后,我们会遇到这样的提示: What is the branch version for "Unnamed - org.myorg:myapp:jar:1.1-SNAPSHOT"? (org.myorg:myapp) 1.1-SNAPSHOT: : ——"分支中的版本号是多少?默认为1.1-SNAPSHOT" 这时我们想要的版本是1.1.1-SNAPSHOT,因此输入1.1.1-SNAPSHOT,回车,maven继续执行直至结束。 接着,我们浏览svn仓库,会看到这样的目录: https://192.168.1.100:8443/svn/myapp/branches/1.1.x/,打开其中的POM文件,其版本已经是1.1.1-SNAPSHOT。 分支创建好了,就可以使用release:prepare和release:perform为1.1.0打标签,升级trunk至1.2.0-SNAPSHOT,然后分发1.1.0。 至此,一切OK。 小结 本文讲述了如何使用Maven结合svn进行版本管理。解释了Maven中SNAPSHOT版本的来由,以及Maven管理版本的规则。并结合SCM的tag和branch概念展示了如何使用maven-release-plugin发布版本,以及创建分支。本文涉及的内容比较多,且略显复杂,不过掌握版本管理的技巧对于项目的正规化管理来说十分重要。Maven为我们提供了一些一套比较成熟的机制,值得掌握。

2015-08-14 · 1 min · 210 words · -

MySQL replace into

MySQL replace into http://my.oschina.net/junn/blog/110213 Replace into是Insert into的增强版。在向表中插入数据时,我们经常会遇到这样的情况: 1、首先判断数据是否存在;2、如果不存在,则插入;3、如果存在,则更新。 在SQL Server中可以这样处理: if not exists (select 1 from t where id = 1) insert into t(id, update_time) values(1, getdate()) else update t set update_time = getdate() where id = 1 那么 MySQL 中如何实现这样的逻辑呢?MySQL 中有更简单的方法: replace into replace into t(id, update_time) values(1, now()); 或 replace into t(id, update_time) select 1, now(); replace into 跟 insert 功能类似,不同点在于: replace into 首先尝试插入数据到表中, 1. 如果发现表中已经有此行数据 (根据主键或者唯一索引判断) 则先删除此行数据,然后插入新的数据。 2. 否则,直接插入新数据。 ...

2015-08-14 · 2 min · 216 words · -

语义化版本, semantic versioning

语义化版本, semantic versioning 版本号格式为v<major>.<minor>.<patch>,如v1.2.3。当有不兼容的改变时,需要增加 major 版本号,如v2.1.0。 MAJOR.MINOR.PATCH 版本格式: 主版本号.次版本号.修订号,版本号递增规则如下: 主版本号: 当你做了不兼容的API 修改, 次版本号: 当你做了向下兼容的功能性新增, 修订号: 当你做了向下兼容的问题修正。 先行版本号及版本编译信息可以加到"主版本号.次版本号.修订号"的后面,作为延伸。 semantic versioning https://semver.org/lang/zh-CN/

2015-08-13 · 1 min · 20 words · -

java 字符串, 比较

java 字符串, 比较 java简单的字符串大小比较——compareTo()方法 在java编程中,我们会偶尔遇到字符串大小比较的问题,compareTo()方法很简单就实现这种功能。该方法用于判断一个字符串是大于、等于还是小于另一个字符串。判断字符串大小的依据是根据它们在字典中的顺序决定的。 语法: Str1.compareTo(Str2); 其返回的是一个int类型值。若Str1等于参数字符串Str2字符串,则返回0;若该Str1按字典顺序小于参数字符串Str2,则返回值小于0;若Str1按字典顺序大于参数字符串Str2,则返回值大于0。 java中的compareto方法,返回参与比较的前后两个字符串的asc码的差值,看下面一组代码 String a="a",b="b"; System.out.println(a.compareto.b); 则输出-1; 若a="a",b="a"则输出0; 若a="b",b="a"则输出1; 单个字符这样比较,若字符串比较长呢?? 若a=“ab”,b=“b”,则输出-1; 若a=“abcdef”,b=“b"则输出-1; 也就是说,如果两个字符串首字母不同,则该方法返回首字母的asc码的差值; 如果首字母相同呢?? 若a=“ab”,b=“a”,输出1; 若a=“abcdef”,b=“a"输出5; 若a=“abcdef”,b=“abc"输出3; 若a=“abcdef”,b=“ace"输出-1; 即参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,返回该不同的字符的asc码差值,如果两个字符串不一样长,可以参与比较的字符又完全一样,则返回两个字符串的长度差值 参考: http://blog.sina.com.cn/s/blog_8a7200cd010104nx.html http://www.blogjava.net/hgc-ghc/archive/2013/03/28/397084.html //char 转String String str = String.valueOf(c); //判断字符大小写 if( Character.isUpperCase(c)) 1、字节数组转换为字符串 byte[] byBuffer = new byte[20]; … … String strRead = new String(byBuffer); strRead = String.copyValueOf(strRead.toCharArray(), 0, byBuffer.length]); 2、字符串转换成字节数组 byte[] byBuffer = new byte[200]; String strInput=“abcdefg”; byBuffer= strInput.getBytes(); ...

2015-08-13 · 1 min · 76 words · -

Fastjson

Fastjson // 序列化 String text = JSON.toJSONString(obj); // 反序列化 Map<String, Object> foo = JSON.parseObject(jsonStr0, Map.class); fastjson 对象转换时重命名字段名 @JSONField(name="total_count") private int totalCount; @JSONField(name="incomplete_results") private boolean incompleteResults = false; Map<String, Object> userMap = JSON.parseObject(o, new TypeReference<Map<String, Object»() {}); 使用Fastjson序列化与反序列化对象 public class JSONobject { private String obj; private String color; public String getObj() { return obj; } public void setObj(String obj) { this.obj = obj; } public String getcolor() { return color; } public void setcolor(String color) { this.color = color; } ...

2015-08-13 · 2 min · 325 words · -

Mockito

Mockito 部分mock (partial mock) 部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing (桩实现) 。 为什么需要部分mock 当需要测试一个组合方法 (一个方法需要其它多个方法协作) 的时候,某个叶子方法 (只供别人调用,自己不依赖其它反复) 已经被测试过,我们其实不需要再次测试这个叶子方法,so,让叶子打桩实现返回结果,上层方法实际调用并测试。 mockito实现部分mock的两种方式: spy和 callRealMethod() spy的原理是,如果不打桩默认都会执行真实的方法,如果打桩则返回桩实现。可以看出spy.size()通过桩实现返回了值100,而spy.get(0)则返回了实际值 List<String> list = new LinkedList<String>(); List<String> spy = spy(list); when(spy.size()).thenReturn(100); spy.add("one"); spy.add("two"); assertEquals(spy.get(0), "one"); assertEquals(100, spy.size()); Channel channel = mock(Channel.class); when(channel.writeAndFlush(obj)).thenReturn(null); // 重置 spy 对象,让 add(1,2) 调用真实方法,返回 3 when(exampleService.add(1, 2)).thenCallRealMethod(); Assert.assertEquals(3, exampleService.add(1, 2)); 一、什么是mock测试,什么是mock对象? 一种替代方案就是使用mocks 从图中可以清晰的看出 mock对象就是在调试期间用来作为真实对象的替代品。 mock测试就是在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试。 知道什么是mock测试后,那么我们就来认识一下mock框架—Mockito 二、什么是Mockito ...

2015-08-13 · 2 min · 352 words · -

powermock

powermock PowerMock LinkageError: MockClassLoader javax/management/MBeanServer{.question-hyperlink} http://stackoverflow.com/questions/20400574/powermock-linkageerror-mockclassloader-javax-management-mbeanserver @RunWith(PowerMockRunner.class) @PowerMockIgnore({“javax.management.*”}) @PrepareForTest(ClassName.class) http://blog.csdn.net/jackiehff/article/details/14000779

2015-08-12 · 1 min · 10 words · -

ConcurrentHashMap

ConcurrentHashMap ConcurrentHashMap 是一个线程安全的Hash Table,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法。ConcurrentHashMap可以做到读取数据不加锁,并 且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,不用对整个ConcurrentHashMap加锁。 jdk1.7 由 Segment 数组、HashEntry 组成,和 HashMap 一样,仍然是数组加链表。 它的核心成员变量: /** * Segment 数组,存放数据时首先需要定位到具体的 Segment 中。 */ final Segment<K,V>[] segments; transient Set<K> keySet; transient Set<Map.Entry<K,V>> entrySet; Segment 是 ConcurrentHashMap 的一个内部类,主要的组成如下: static final class Segment<K,V> extends ReentrantLock implements Serializable { private static final long serialVersionUID = 2249069246763182397L; // 和 HashMap 中的 HashEntry 作用一样,真正存放数据的桶 transient volatile HashEntry<K,V>[] table; transient int count; transient int modCount; transient int threshold; final float loadFactor; } 和 HashMap 非常类似,唯一的区别就是其中的核心数据如 value ,以及链表都是 volatile 修饰的,保证了获取时的可见性。 ...

2015-08-12 · 8 min · 1510 words · -

A cycle was detected in the build path of project

A cycle was detected in the build path of project 解决Eclipse中Java工程间循环引用而报错的问题 如果我们的项目包含多个工程 (project) ,而它们之间又是循环引用的关系,那么Eclipse在编译时会抛出如下一个错误信息: “A cycle was detected in the build path of project: XXX” 解决方法非常简单: Eclipse Menu -> Window -> Preferences… -> Java -> Compiler -> Building -> Building path problems -> Circular dependencies -> 将Error改成Warning http://blog.csdn.net/kcai678/article/details/4668993

2015-08-10 · 1 min · 48 words · -

archlinux hibernate

archlinux hibernate edit config file /etc/mkinitcpio.conf add resume field sudo vim /etc/mkinitcpio.conf HOOKS=(base udev resume autodetect modconf block filesystems keyboard fsck) Configure the initramfs When an initramfs with the base hook is used, which is the default, the resume hook is required in /etc/mkinitcpio.conf. Whether by label or by UUID, the swap partition is referred to with a udev device node, so the resume hook must go after the udev hook. This example was made starting from the default hook configuration: ...

2015-08-08 · 1 min · 155 words · -