一、背景资料
memcached本身是集中式的缓存系统,要搞多节点分布,只能通过客户端实现。memcached的分布算法一般有两种选择:
1、根据hash(key)的结果,模连接数的余数决定存储到哪个节点,也就是hash(key)% sessions.size(),这个算法简单快速,表现良好。然而这个算法有个缺点,就是在memcached节点增加或者删除的时候,原有的缓存数据将大规模失效,命中率大受影响,如果节点数多,缓存数据多,重建缓存的代价太高,因此有了第二个算法。
2、Consistent Hashing,一致性哈希算法,他的查找节点过程如下:
首先求出memcached服务器(节点)的哈希值,并将其配置到0~232的圆(continuum)上。然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。
一致性哈希算法来源于P2P网络的路由算法,更多的信息可以读这里。二、测试报告
spymemcached和xmemcached都实现了一致性哈希算法(其实我是照抄的),这里要测试下在使用一致性哈希的情况下,增加节点,看不同散列函数下命中率和数据分布的变化情况,这个测试结果对于spymemcached和xmemcached是一样的,测试场景:
从一篇英文小说(《黄金罗盘》前三章)进行单词统计,并将最后的统计结果存储到memcached,以单词为key,以次数为value。单词个数为 3061,memcached原来节点数为10,运行在局域网内同一台服务器上的不同端口,在存储统计结果后,增加两个memcached节点(也就是从10个节点增加到12个节点),统计此时的缓存命中率并查看数据的分布情况。
结果如下表格,命中率一行表示增加节点后的命中率情况(增加前为100%),后续的行表示各个节点存储的单词数,CRC32_HASH表示采用CRC32 散列函数,KETAMA_HASH是基于md5的散列函数也是默认情况下一致性哈希的推荐算法,FNV1_32_HASH就是FNV 32位散列函数,NATIVE_HASH就是java.lang.String.hashCode()方法返回的long取32位的结果,MYSQL_HASH是xmemcached添加的传说来自于mysql源码中的哈希函数。
结果分析:
1、命中率最高看起来是NATIVE_HASH,然而NATIVE_HASH情况下数据集中存储在第一个节点,显然没有实际使用价值。为什么会集中存储在第一个节点呢?这是由于在查找存储的节点的过程中,会比较hash(key)和hash(节点IP地址),而在采用了NATIVE_HASH的情况下,所有连接的hash值会呈现一个递增状况(因为String.hashCode是乘法散列函数),如:
192.168.0.100:12000 736402923
192.168.0.100:12001 736402924
192.168.0.100:12002 736402925
192.168.0.100:12003 736402926
如果这些值很大的会,那么单词的hashCode()会通常小于这些值的第一个,那么查找就经常只找到第一个节点并存储数据,当然,这里有测试的局限性,因为memcached都跑在一个台机器上只是端口不同造成了hash(节点IP地址)的连续递增,将分布不均匀的问题放大了。
2、从结果上看,KETAMA_HASH维持了一个最佳平衡,在增加两个节点后还能访问到83.3%的单词,并且数据分布在各个节点上的数目也相对平均,难怪作为默认散列算法。
3、最后,单纯比较下散列函数的计算效率:
CRC32_HASH:3266
KETAMA_HASH:7500
FNV1_32_HASH:375
NATIVE_HASH:187
MYSQL_HASH:500
NATIVE_HASH > FNV1_32_HASH > MYSQL_HASH > CRC32_HASH > KETAMA_HASH
一、概述
1.nmon介绍
2.nmon下载、安装及使用
3.nmon analysis 分析及使用,各个项的含义
二、详细信息:
1.nmon介绍:
nmon(Nigel's Monitor)是由
IBM公司提供的、免费监控AIX系统与
Linux系统资源的工具,该工具可以将服务器系统资源消耗的数据收集起来并输出一个特定的文件,再使用分析工具(nmon analyser)进行数据统计分析。
nmon主要记录以下方面的数据:
CPU占用率
内存使用情况
磁盘I/O速度、传输和读写比率、错误统计率与传输包的大小
消耗最多的进程
计算机详细信息和资源
页面空间和页面I/O速度
用户自定义的磁盘组
网络文件系统
Step1.执行nmon工具命令,nmon工具会将输出的内容显示到计算机屏幕,同时生成一份nmon文件
Step3.该分析工具将收集到的数据绘制成相关的图表,供分析使用
2.nmon下载、安装及使用
nmon下载地址:
官网下载地址:下载linux 对应的 nmon
其它方式下载:http://down.51cto.com/data/849411
a.安装:下载完后,将其上传到linux下的某个目录下,运行命令tar –xvf file.tar,解压后

b.修改权限chmod nmon_linux_x86,
c.运行./nmon_linux_x86 -f -r test -s 10 -c 15,此时会生成一个test文件,主要是把监测的结果实时的写进该文件
d.运行./nmon_linux_x86,出现监测主窗口,按照菜单输入相应的字母,即可监测,比如输入c,m,d,n等,即监测CPU,Memory,Disks,Netword
e.一段时间后,将生成的test.nmon文件转化成csv文件,sort test.nmon >test.csv,然后download wondinds本地
f.打开nmon analysis 工具,导入test.csv,即生成如下图
3.nmon analysis 分析及使用,各个项的含义
具体可以google或者百度或者参考nmon analysis user guide,这里不再赘述
一、下载jdk
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
二、 安装
在/usr下新建
java文件夹,将安装包放在/usr/java目录下
# mkdir /usr/java
文件安装
// # chmod 777 jdk-1_5_0_14-linux-i586-rpm.bin ← 修改为可执行
// # ./jdk-1_5_0_14-linux-i586-rpm.bin ← 选择yes同意上面的协议
# rpm -ivh jdk-7u15-linux-x64.rpm 安装完毕
(补充:这一部分使用rpm命令需要root用户权限,否则会出现错误:error: can't create transaction lock on /var/lib/rpm/__db.000,如果无法获得root权限,比如在集群上使用并非管理员时,可以选择.tar.gz的安装包
在我的实验中是选用的.tar.gz的安装包,因此使用以下命令解压之后即可
tar -xvzf jdk-7u51-linux-x64.gz ,然后进入下一步的环境变量配置步骤:
export JAVA_HOME=/home/ycai/opt/jdk1.7.0_51
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
详细解释请看下文。
)
检测是否安装成功
#java -version
显示
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) 64-Bit Server VM (build 21.0-b17, mixed mode)
三. 需要配置的环境变量
1. PATH环境变量。作用是指定命令搜索路径,在
shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序。我们需要把 jdk安装目录下的bin目录增加到现有的PATH变量中,bin目录中包含经常要用到的可执行文件如javac/java/javadoc等待,设置好 PATH变量后,就可以在任何目录下执行javac/java等工具了。
2. CLASSPATH环境变量。作用是指定类搜索路径,要使用已经编写好的类,前提当然是能够找到它们了,JVM就是通过CLASSPTH来寻找类的。我们 需要把jdk安装目录下的lib子目录中的dt.jar和tools.jar设置到CLASSPATH中,当然,当前目录“.”也必须加入到该变量中。
3. JAVA_HOME环境变量。它指向jdk的安装目录,Eclipse/NetBeans/Tomcat等软件就是通过搜索JAVA_HOME变量来找到并使用安装好的jdk。
四. 三种配置环境变量的方法1. 修改/etc/profile文件
如果你的计算机仅仅作为开发使用时推荐使用这种方法,因为所有用户的shell都有权使用这些环境变量,可能会给系统带来安全性问题。
·用文本编辑器打开/etc/profile
·在profile文件末尾加入:
export JAVA_HOME=/usr/share/jdk1.6.0_14 export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar |
1. 永久修改,对所有用户有效
# vi /etc/profile //按键盘[Shift + g], 在profile文件最后添加下面的内容: export JAVA_HOME = /home/myuser/jdk1.7.0_03 export PATH = $JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar |
[注]:修改文件后如果想马上生效,还要运行 #source /etc/profile
2. 永久修改,对单一用户有效
//修改用户目录下的.bash_profile文件 $ vi /home/myuser/.bash_profile //在文件最后添加下面的内容 export JAVA_HOME = /home/myuser/jdk1.7.0_03 export PATH = $JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar |
[注]:修改文件后如果想马上生效,还要运行 #source /home/myuser/.bash_profile
3. 只对当前bash /shell 生效
$ export JAVA_HOME = /home/myuser/jdk1.7.0_03
$ export PATH = $JAVA_HOME/bin:$PATH
$ export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
五、测试配置环境
写个简单的HelloWorld来测试一下
[root@esprit java]# vi HelloWorld.java
文件中输入:
public class HelloWorld {
public static void main(String args[]) {
System.out.println( " Hello World in Linux!! " );
}
}
:wq 保存退出
[root@esprit java]# javac HelloWorld.java
没有错误,接着
[root@esprit java]# java HelloWorld
shell下输出:Hello World in Linux!!
最近在复习oracle数据库,只能说oracle数据库实在是太强大了,当然
学习起来也就复杂了。下面是使用oracle的分页算法的存储过程,拿出来大家参考一下吧。
我认为其中涉及到的包,游标,exception是有点难理解难记忆的,大家可以参考一下相关的书籍好好理解理解~~
//oracle分页存储过程 create or replace proceduce fenye(tableName in varchar2,pageSize in number,pageNow in number,myRowCount out number,myPageCount out number, p_cursor out t1.t---返回记录数的游标 ) is --定义部分 v_sql varchar2(500); v_begin number:=(pageNow-1)*pageSize+1; v_end number:=pageNow*pageSize; begin --开始执行部分 v_sql:='select * from (select t1.*,rownum rn from(select * from '||tableName||') t1 where rownum<='||v_end||')where rn>='||v_begin||'':这表示显示的是第六到第十页的数据 --把游标和sql语句关联 open p_cursor for v_sql; --计算myRowCount和myPageCount v_sql:='select count(*)from '||tableName||''; execute immediate v_sql into myRowCount--执行sql语句并把返回的值赋给myRowCount --计算myPageCount if mod(myRowCount,pageSize)=0 then myPageCount:=myRowCount/pageSize; else myPageCount:=myRowCount/pageSize+1; end if; --关闭游标 close p_cursor; end; |
1.jps:查看当前运行着的java进程(仿linux下的ps),显示进程号 2. jinfo: 查参数jinfo -flagPermSize 2208(进程号)
jinfo -flag MaxPermSize 2208(进程号) C:\Users\WILL>jinfo Usage: jinfo <option> <pid> (to connect to a running process) where <option> is one of: -flag <name> to print the value of the named VM flag -flag [+|-]<name> to enable or disable the named VM flag -flag <name>=<value> to set the named VM flag to the given value -h | -help to print this help message |
3. jconsole 2208
用法:
jconsole [ -interval=n ] [ -notile ] [ -pluginpath <path> ] [ -version ] [ connection ...] -interval 将更新间隔时间设置为 n 秒(默认值为 4 秒) -notile 最初不平铺显示窗口(对于两个或更多连接) -pluginpath 指定 jconsole 用于查找插件的路径 -version 输出程序版本 connection = pid || host:port || JMX URL (service:jmx:<protocol>://...) pid 目标进程的进程 ID host 远程主机名或 IP 地址 port 用于远程连接的端口号 -J 对正在运行 jconsole 的 Java 虚拟机指定 |
输入参数
4. jstack 2208列出所有线程,以及线程的运行状态
C:\Users\WILL>jstack Usage: jstack [-l] <pid> (to connect to running process) Options: -l long listing. Prints additional information about locks -h or -help to print this help message |
5. jstat -gcutil 2208 1000(每隔1000毫秒打印一次信息) 10(打印10行)
C:\Users\WILL>jstat invalid argument count Usage: jstat -help|-options jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] Definitions: <option> An option reported by the -options option <vmid> Virtual Machine Identifier. A vmid takes the following form: <lvmid>[@<hostname>[:<port>]] Where <lvmid> is the local vm identifier for the target Java virtual machine, typically a process id; <hostname> is the name of the host running the target Java virtual machine; and <port> is the port number for the rmiregistry on the target host. See the jvmstat documentation for a more complete description of the Virtual Machine Identifier. <lines> Number of samples between header lines. <interval> Sampling interval. The following forms are allowed: <n>["ms"|"s"] Where <n> is an integer and the suffix specifies the units as milliseconds("ms") or seconds("s"). The default units are "ms". <count> Number of samples to take before terminating. -J<flag> Pass <flag> directly to the runtime system. |
C:\Users\WILL>jstat -options
-class
-compiler
-gc
-gccapacity
-gccause
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-printcompilation
6. jmap把虚拟机里运行着的所有文件都down下来,相当于快照
C:\Users\WILL>jmap Usage: jmap -histo <pid> (to connect to running process and print histogram of java object heap jmap -dump:<dump-options> <pid> (to connect to running process and dump java heap) dump-options: format=b binary default file=<file> dump heap to <file> Example: jmap -dump:format=b,file=heap.bin <pid> |
7. jhat 对jmap下来的文件进行分析,多个角度
Usage: jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [- debug <int>] [-version] [-h|-help] <file> -J<flag> Pass <flag> directly to the runtime system. For example, -J-mx512m to use a maximum heap size of 512MB -stack false: Turn off tracking object allocation call stack. -refs false: Turn off tracking of references to objects -port <port>: Set the port for the HTTP server. Defaults to 7000 -exclude <file>: Specify a file that lists data members that should be excluded from the reachableFrom query. -baseline <file>: Specify a baseline object dump. Objects in both heap dumps with the same ID and same class will be marked as not being "new". -debug <int>: Set debug level. 0: No debug output 1: Debug hprof file parsing 2: Debug hprof file parsing, no server -version Report version number -h|-help Print this help and exit <file> The file to read For a dump file that contains multiple heap dumps, you may specify which dump in the file by appending "#<number>" to the file name, i.e. "foo.hprof#3". All boolean options default to "true" |
图片又不能上传。。。就打印出这些帮助参数来,能看懂得了。
测试驱动开发(Test-driven development)是极限编程中倡导的程序开发方法,以其倡导先写测试程序,然后编码实现其功能得名。
正面评价
可以有效的避免过度设计带来的浪费。但是也有人强调在开发前需要有完整的设计再实施可以有效的避免重构带来的浪费。
可以让开发者在开发中拥有更全面的视角。
负面评价
开发者可能只完成满足了测试的代码,而忽略了对实际需求的实现。有实践者认为用结对编程的方式可以有效的避免这个问题。
会放慢开发实际代码的速度,特别对于要求开发速度的原型开发造成不利。这里需要考虑开发速度需要包含功能和品质两个方面,单纯的代码速度可能不能完全代表开发速度。
对于GUI,资料库和Web应用而言。构造
单元测试比较困难,如果强行构造单元测试,反而给维护带来额外的
工作量。有开发者认为这个是由于设计方法,而不是开发方法造成的困难。
使得开发更为关注用例和测试案例,而不是设计本身。目前,对于这个观点有较多的争议。
测试驱动开发会导致单元测试的覆盖度不够,比如可能缺乏边界测试。在实际的操作中,和非测试驱动开发一样,当代码完成以后还是需要补充单元测试,提高测试的覆盖度。
测试驱动开发 - 开发过程
概括起来,测试驱动开发的基本过程如下:
(1) 明确当前要完成的功能。可以记录成一个 TODO 列表。
(3) 测试代码编译不通过。
(4) 编写对应的功能代码。
(5) 测试通过。
(6) 对代码进行重构,并保证测试通过。
(7) 循环完成所有功能的开发。
Nightwatch是一套新近问世的基于Node.js的
验收测试框架,使用
Selenium WebDriver API以将Web应用测试自动化。它提供了简单的语法,支持使用JavaScript和CSS选择器,来编写运行在Selenium服务器上的端到端测试。
不同于行为驱动测试(BDD)和
单元测试独立运行并使用模拟/存根,端到端测试将试着尽可能从用户的视角,对真实系统的访问行为进行仿真。对Web应用来说,这意味着需要打开浏览器、加载页面、运行JavaScript,以及进行与DOM交互等操作。Nightwatch尝试着使用语法糖(syntax sugar)来实现这一目标:
this.demoTestGoogle = function (browser) { browser .url(“http://www.google.com”) .waitForElementVisible('body', 1000) .setValue('input[type=text]', 'nightwatch') .waitForElementVisible('button[name=btnG]', 1000) .click('button[name=btnG]') .pause(1000) .assert.containsText('#main', 'The Night Watch') .end(); }; |
除简化了编写
自动化测试的过程外,Nightwatch还能够与持续集成的流水作业结合,从而对开发中的系统进行完整的诊断:我们可以从Nightwatch网站找到当前提供特性的列表:
简单但强大的语法。只需要使用JavaScript和CSS选择器,开发者就能够非常迅捷地撰写测试。开发者也不必初始化其他对象和类,只需要编写测试规范即可。
内建命令行测试运行器,允许开发者同时运行全部测试——分组或单个运行。
自动管理Selenium服务器;如果Selenium运行在另一台机器上,那么也可以禁用此特性。
支持持续集成:内建
JUnit XML报表,因此开发者可以在构建过程中,将自己的测试与系统(例如Hudson 或Teamcity等)集成。
使用CSS选择器或Xpath,定位并验证页面中的元素或是执行命令。
易于扩展,便于开发者根据需要,实现与自己应用相关的命令。
目前,Selenium是JavaScript的世界里验收测试方面最流行的工具之一,类似的还有PhantomJS。
二者都有其独到的方法:Selenium使用其WebDriver API,而PhantomJS使用无界面的WebKit浏览器。它们都是非常成熟的工具,都具有强大的社区支持。
它们与Nightwatch之间最大的不同,主要是在于语法的简易度以及对持续集成的支持。与Nightwatch相比,Selenium和PhantomJS都拥有更加冗长的语法,这会让编码变得更庞大,而且不支持从命令行中进行开箱即用的持续集成(JUnit XML或其他标准输出)。
尽管如此,Nightwatch还处于不断演进的道路上,以成为更加成熟工具的。在
Google Groups中,WD.js(另一个基于Node.js的验收测试框架)的作者Sebastian Vincent针对处理回调所选择的实现给出了一些批评意见:
当涉及异步调用时,基于链式的队列是个糟糕的模式。如果开发者想要做一些复杂的事情,或是组合一些东西,最终将不得不手动停止队列以插入任务(但也许Nightwatch会证明我的看法是错的)。
Vincent还针对Nightwatch和Selenium服务器之间使用的底层通信协议,指出了其中存在的不足之处:
Nightwatch离成熟还远,看看HTTP协议,GET和DETLETE中没有重试、没有超时设置,也没有内容/长度+内容类型。在非直接情况下(例如Sauce-connect或排队),它很快就会出现问题。
然而,哪怕有这些批评的声音,Nightwatch还是入选了GitHub本月最热门代码仓库。另外该团队运营着一个Twitter账号,听取来自社区的反馈并与开发者互动。
1、定义
原型模式(Prototype)就是通过复制一个已经存在的实例来返回新的实例,而不是新建实例,被复制的实例就是我们所称的原型对象,这个原型是可定制的。
2、原理
有两部分组成,抽象原型和具体原型。意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
3、原型模式UML图
4、实现
1>使用一个原型管理器;
2>实现克隆操作(浅拷贝和深拷贝);
3>初始化克隆对象。
5、示例程序
(1)利用Java中的clone方法深拷贝与浅拷贝
浅拷贝:
public class Professor { private String address; private double salary; public Professor(String address, double salary) { this.address = address; this.salary = salary; } public void setAddress(String address) { this.address = address; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "Professor [address=" + address + ", salary=" + salary + "]"; } } public class Student implements Cloneable { private String name; private int age; private Professor professor; public Student(String name, int age, Professor professor) { this.name = name; this.age = age; this.professor = professor; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", Professor=" + professor.toString() + "]"; } @Override public Object clone() { Student student = null; try { // 在运行时,Object中的clone识别出你要复制的是哪一个对象,Object中的clone() // 然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。 student = (Student) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return student; } |
public static void main(String[] args) { Professor professor = new Professor("beijing", 12.0); Student s1 = new Student("zhangsan", 18, professor); Student s2 = (Student) s1.clone(); System.out.println(s1); System.out.println(s2); System.out.println("**************************************"); s2.name = "lisi"; s2.age = 20; s2.professor.setAddress("shanghai"); s2.professor.setSalary(230.0); System.out.println(s1); System.out.println(s2); } } Student [name=zhangsan, age=18, Professor=Professor [address=beijing, salary=12.0]] Student [name=zhangsan, age=18, Professor=Professor [address=beijing, salary=12.0]] ************************************** Student [name=zhangsan, age=18, Professor=Professor [address=shanghai, salary=230.0]] Student [name=lisi, age=20, Professor=Professor [address=shanghai, salary=230.0]] |
深拷贝:
public class Professor2 implements Cloneable { private String address; private double salary; public Professor2(String address, double salary) { this.address = address; this.salary = salary; } public void setAddress(String address) { this.address = address; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "Professor2 [address=" + address + ", salary=" + salary + "]"; } @Override public Object clone() { Professor2 o = null; try { o = (Professor2) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } } |
public class Student2 implements Cloneable { private String name; private int age; private Professor2 professor; public Student2(String name, int age, Professor2 professor) { this.name = name; this.age = age; this.professor = professor; } @Override public String toString() { return "Student2 [name=" + name + ", age=" + age + ", Professor2=" + professor.toString() + "]"; } @Override public Object clone() { Student2 o = null; try { // 在运行时,Object中的clone识别出你要复制的是哪一个对象,Object中的clone() // 然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。 o = (Student2) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } o.professor = (Professor2) professor.clone(); return o; } public static void main(String[] args) { Professor2 professor = new Professor2("beijing", 12.0); Student2 s1 = new Student2("zhangsan", 18, professor); Student2 s2 = (Student2) s1.clone(); System.out.println(s1); System.out.println(s2); System.out.println("**************************************"); s2.name = "lisi"; s2.age = 20; s2.professor.setAddress("shanghai"); s2.professor.setSalary(230.0); System.out.println(s1); System.out.println(s2); } } Student2 [name=zhangsan, age=18, Professor2=Professor2 [address=beijing, salary=12.0]] Student2 [name=zhangsan, age=18, Professor2=Professor2 [address=beijing, salary=12.0]] ************************************** Student2 [name=zhangsan, age=18, Professor2=Professor2 [address=beijing, salary=12.0]] Student2 [name=lisi, age=20, Professor2=Professor2 [address=shanghai, salary=230.0]] |
模拟clone方法进行浅拷贝
public interface Prototype { public Prototype clone(); public void setName(String name); public String getName(); } <span style="font-size:14px;">public class ConcretePrototypeA implements Prototype { private String name; public ConcretePrototypeA() { } public ConcretePrototypeA(String name) { this.name = name; } @Override public void setName(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public Prototype clone() { ConcretePrototypeA prototype = new ConcretePrototypeA(); prototype.setName(this.name); return prototype; } @Override public String toString() { return "ConcretePrototypeA [name=" + name + "]"; } }</span> public class TestPrototype { public static void main(String[] args) { ConcretePrototypeA prototypeA = new ConcretePrototypeA("jimmy"); ConcretePrototypeA prototypeA2 = (ConcretePrototypeA) prototypeA .clone(); System.out.println(prototypeA); System.out.println(prototypeA2); } } ConcretePrototypeA [name=jimmy] ConcretePrototypeA [name=jimmy] |
6、应用场景
系统需要创建的对象是动态加载的,而且产品具有一定层次时,可以考虑使用原型模式。原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据。
1>当要实例化的类是在运行时刻指定时,例如,通过动态装载;
2>或者为了避免创建一个与产品类层次平行的工厂类层次时;
3>或者当一个类的实例只能有几个不同状态组合中的一种时。
4>建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
比如有一个对象,在某一时刻该对象中已经包含了一些有效的值,此时可能会需要一个和该对象完全相同的新对象,并且此后对新对象的任何改动都不会影响到原来对象中的值,也就是说新对象与原来的对象是两个独立的对象,但新对象的初始值是由原来的对象确定的。
7、赋值创建对象
1>java中赋值创建对象是可以实现对象的重用的,但是新对象和原对象是同一个引用;如果修改其中的一个对象的值,则另外的一个对象也会发生改变。
2>使用clone方法会返回对象的一个拷贝,这样一来,如果修改一个对象的值,则另外的对象不会发生改变的。
8、拷贝分为"浅拷贝"和"深拷贝"
浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制(那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象)。换言之,深复制把重复的对象所引用的对象都复制一遍,而这种对被引用到的对象的复制叫做间接复制。
<span style="font-size:14px"></span>
Tempest是Openstack的集成
测试框架,它的实现基于
python的unittest2测试框架和nose测试框架。Tempest对Openstack终端发起一系列API请求,并且对终端的响应进行验证。Tempest通过config文件来描述整个测试环境,包括compute API端点,Keystone
server以及Glance server安装的镜像的UUID等信息。以下是Tempest的目录结构:
Tempest的优点
1.Tempest可以自动寻找,执行测试:自动查找当前目录下所有以[Tt]est开头的Python源文件,并且按此规则递归查找子目录;所有以[Tt]est开头的Python源文件里所有以[Tt]est开头的function和class,以及继承自unittest.TestCase的class(不需要以[Tt]est开头)都会被执行。
2.Tempest可以指定文件、模块、函数进行测试。
3.Tempest可以指定类型进行测试。
4.Tempest可扩展性强,可以方便的在tempest中添加其他
测试用例,可以整合其他类型测试例如压力测试、场景测试等。
Tempest配置
1.git下载Tempest后,在Tempest根目录下拷贝一份配置文件tempest.conf:
cp etc/tempest.conf.sample etc/tempest.conf
2.配置tempest.conf ,主要配置以下几个属性:
配置identity (Keystone) 的host
配置Compute (Nova) 的username、password、 tenant_name和alt_username、alt_password、alt_tenant_name(均不是管理员用户。配置两个不同的用户,测试普通用户不能更改和删除其他用户的image、server等)
配置Compute (Nova) 的image_ref和image_ref_alt(配置两个不同的image ID)
配置Image (Glance) 的ssh user
配置compute-admin和identity-admin的管理员用户名、密码和tenant名。
使用Tempest进行测试
执行整个tempest测试框架:nosetests tempest
指定文件测试,例如:nosetests tempest.api.compute.flavors.test_flavors.py
指定模块进行测试,例如:nosetests tempest.api.compute.flavors.test_flavors.py:FlavorsTestJSON
指定函数进行测试,例如:nosetests tempest.api.compute.flavors.test_flavors.py:FlavorsTestJSON.test_list_flavors
指定类型进行测试,例如 :tempest –s 只执行smoke类型测试
指定特定的attr的用例进行测试,例如:nosetests –a type=’gate’ 只执行attr为type=’gate’的测试
API测试用例
tempest.api是openstack api测试用例集。以函数test_list_flavors的执行举例,以下是该用例执行时各类间的继承和调用:
FlavorTestJSON继承自BaseComputeTest。Clients是负责管理包括FlavorsClient在内的所有的openstack clients的,同时调用TempestConfig来读取配置文件。FlavorsClient继承自RestClient,封装了访问openstack api的接口。FlavorsTestJSON通过FlavorsClient来实现对openstack api的访问。
测试结果举例:
对Tempest的扩展
1.对tempest中的测试用例进行了扩展,添加了产品自研模块和功能的测试用例。
2. 对测试机制进行完善,并且在tempest中加入异常分支检查。
3.在tempest中植入其他测试工具如burnintest。
3. 在tempest基础上做了二次开发,开发了稳定性测试工具,测试系统在openstack时间有负载的情况下的可靠性和可用性。
Sauce Labs扩展了Appium,支持对
Android应用和Firefox OS应用进行
自动化测试。今年年初又引入了对iOS的支持。
Appium包括如下主要特性:
·开发者可以测试原生、混合和移动Web应用
·可用于实际设备或模拟器/仿真器上
·可以用一个脚本测试iOS应用和Android应用
·移动Web应用通常需要一个独立的测试脚本,该脚本与测试原生应用所用脚本不同,因为包含在Web页面中的图形元素和这些页面的结构存在较大差异
·要执行测试,Appium需要与Apple的UIAutomation库和Android的UiAutomator框架(API版本号大于16)进行交互。对于Android的早期版本,Appium使用了Selendroid这种扩展
在使用Appium进行测试时,应用无需重新编译。测试可以使用Selenium WebDriver所支持的任何语言编写,包括Java、Objective-C、JavaScript、PHP、
Python、
Ruby、C#、Clojure、Perl和Haskell等,还可以使用任何测试框架,包括Junit、Rspec、PHPUnit、Nose、Mocha、Cucumber、Capybara和Vows等。Mozilla最近实现了WebDriver API,并以此向Firefox OS中加入自动化测试,这样Sauce Labs就可以很方便地扩展Appium来支持该移动Web OS了。在GTAC 2013期间,Sauce Labs的高级软件工程师Jonathan Lipps演示了如何在Firefox OS上运行自动化测试(参考Firefox OS演示的33分50秒)。Sauce Labs开源了Appium。为支持其开发,该公司还在可以按需扩展的云环境中提供了模拟器/仿真器,可以在这上面进行自动化
移动测试。