使用JTop查询cpu高的线程 三月 27th, 2012
要求程序打开jmx,
然后使用jconsole连接:
C:\Program Files\Java\jdk1.6.0_27\bin>jconsole -pluginpath "C:\\Program Files\\Java\\jdk1.6.0_27\\demo\\management\\JTop\\JTop.jar"
在JTop Tab找到CPU高的线程以后,再看线程Tab,找到运行上下文即可。
android手机系统app备份和恢复 二月 21st, 2011
备份app使用adb shell pull和adb shell push的方式。
比如备份浏览器到pc:
adb pull /system/app/Browser.odex adb pull /system/app/Browser.apk
恢复app:
adb push Browser.apk /system/app/Browser.apk adb push Browser.odex /system/app/Browser.odex
注意,还要修改权限和系统的app相同,我的nexus s权限是644。
test@test-desktop:~/backup/nexuss$ adb shell # cd /system/app/ # chmod 644 Browser.apk # chmod 644 Browser.odex
git常用命令 一月 31st, 2011
1.建立仓库
git init
2.提交文件
git add * git commit -m 'first commit'
3.同步代码到服务器
git remote add origin git@github.com:imcaptor/android-gesture-samples.git git push origin master
4.更新代码
git pull origin master
5.建立本地分支,牵出本地分支,修改代码,提交,同步到远程服务器
git branch testbranch1
git checkout testbranch1
git commit 文件名
git push origin testbranch1
6.合并分支到主干
git checkout master
git merge testbranch1
unbuntu下面编译android源码 十二月 28th, 2010
1. 安装必要的软件:
sudo apt-get install git-core gnupg valgrind flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev sun-java5-jdk
2.Installing Repo
$ curl http://android.git.kernel.org/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
$ mkdir working-directory-name
$ cd working-directory-name
$ repo init -u git://android.git.kernel.org/platform/manifest.git -b android-2.1_r2 #获取2.1分支
3.同步代码
repo sync
4.编译代码
make
5.编译某个app
. build/envsetup.sh
lunch 1
mmm packages/apps/Launcher
6.导入eclipse
cp development/ide/eclipse/.classpath .
7.新建项目,选择签出代码目录
repo sync4.编译代码
. build/envsetup.sh lunch 1 mmm packages/apps/Launcher6.导入eclipse
cp development/ide/eclipse/.classpath .
7.新建项目,选择签出代码目录
android开发不能指望GC,有时需要主动释放内存 九月 12th, 2010
尤其是比较占内存的Bitmap,不需要展示的时候要调用bitmap.recycle(),以快速释放内存。
否则等GC释放时,已经报内存溢出的错误了。
ssh自动登录并且su的脚本 九月 12th, 2010
从一台机器sshhost上用u1用户自动登录到, 然后su成u2
- 需要安装expect
- 脚本如下:
#!/usr/bin/expect
#auto ssh login
set timeout 10
set sshhost test.sshhost.com
set u1 "first_user"
set p1 "first_password"
set u2 "second_user"
set p2 "second_password"
spawn ssh -l$u1 -p22 $sshhost
expect {
"yes/no" {
send "yes\r"
exp_continue
} "*assword:*" {
send "$p1\r"
exp_continue
} "*ast login:*" {
# 在s1上变成u2/p2用户:
send "LANG=en_US.UTF-8\r"
expect "\$*"
send "su - $u2\r"
expect "*assword:*"
send "$p2\r"
interact
exit 0
} timeout {
send_user "connection to $sshhost timeout!\n"
exit 1
} "*ncorrect*" {
send_user "password incorrect!\n"
exit 2
} "*ermission*" { #for LINUX ssh
send_user "password Error!\n"
exit 2
} eof {
exit 3
}
}
使用springsource roo生成代码 给dao说goodby? 八月 12th, 2010
看着教程,一步一步来:
G3 HERO手机通过蓝牙分享软件不支持中文名 七月 28th, 2010
G3 HERO手机通过蓝牙分享软件不支持中文名
一个J2EE的项目的痛苦经历(03年的项目) 七月 22nd, 2010
一个J2EE的项目的痛苦经历
经过四个多月的开发工作,项目终于基本上做完了,因为是第一次做J2EE架构的项目,所以遇到了困难,但是也明白了一些东西。
系统架构
图中所示,
-
工具类和值对象是所有的系统都依赖的包,值对象没有任何业务逻辑,仅仅是数据结构,工具类是服务定位、数据源获得、异常、日期转换等通用类,它可以被所有的层次所访问。
-
数据访问层是对数据的访问,它是一些CMP和普通的JDBC访问类,因为有些地方用EJB访问效率比较低,所以没有所有的地方都使用EJB Query或Finder,并且所有的CMP也都是Local的。
-
访问外部系统接口是对外部系统访问的封装,因为可能在不同的业务逻辑里都需要对外部系统访问。
-
“可重用的业务逻辑”,这个名字我也不知道怎么叫,但这是它的本质,它可以被重用,而本身又不是任何完整的业务逻辑,它是一些普通的java类,没有必要使用EJB,使用普通类更灵活。
-
“面向需求用例的业务逻辑”,这个名字也很拗口,但这也是它的本质,一个接口至少可以完成一个需求用例里的一个交互,这一层主要负责业务逻辑,以及事务。它是许多stateless sessionbean组成的,它都是remote的,为了client调用的方便,所有的ejb都用了一个单子的普通java类(我们都叫webctrl)来发现服务,调用服务,一是让客户端调用方便,二是让客户端编译期和EJB没有关系,以后即使不使用EJB,客户端代码也不需要修改。
-
给外部系统提供的服务,是一些接口,可能是socket的,也可能是SOAP的,他们都是EJB Client。主要负责参数的接受,以及调用结果的转换。
-
Web展现层,主要负责业务流程的控制,展现,以及数据的传递。
每一层都有很多并列的子系统,原则上子系统之间不可以互相访问。
每一层的职责都很清楚,不是你做的事情,千万不要做。
分了这么多层,每一层又有很多子系统,确实工作容易分配了,而且也避免了出现太多的重复代码,需求的变更可能在某个地方加一个控制就可以了。但是测试和代码的更新带来了很多麻烦。
先说测试,到现在我都不知道有什么好的办法测试local的ejb,因为它是local的,只有在应用服务器里面才能调用它,当时是先做一个remote的session bean,在里面调用local的CMP,然后再使用jbuilder的向导生成session bean的测试代码。这样太麻烦了。这涉及到任务安排的问题,普通的开发都是从底向上顺序进行,其实也可以把底层的框架写出来,上层可以编译就可以了,上层可以直接作为底层的测试驱动,等底层开发好了,直接测试上面一层即可。
代码的更新也很头痛,值对象ValueObject增加了一个字段,数据访问要更改,业务逻辑要更改,虽然改动都很小,但是程序员觉得很麻烦,得到最新代码,改一两个地方,编译。如果不更新代码,服务器和客户端VO不一致,java会报一个序列号不一致的错误。后来采用了一种办法,所有的项目都使用jbuilder来编辑,编译,依赖的包都使用相对路径(项目目录下生成一个library文件),每个人编译的结果也要检入到一个地方。这样只要得到最新二进制代码,就可以用最新的编译,运行。
最痛苦的几个事情
-
臭名昭著的NoSuchMethodException,这个异常你经常见到吧,就是在你作为客户程序员在编译的时候使用了服务类的一个方法method1,到了运行期间服务器使用了旧版本,没有method1,就会报这个异常。我一开始以为是我们内部的代码版本不一致问题,但是都是将最新的代码发布到weblogic上面,还是有这个错误。后来沿着报异常的行号,发现是weblogic的ejb生成代码里报的错,我把生成代码打开看了一下,发现生成的是weblogic sp1版本的,而服务器上是weblogic sp2的版本。看来开发的时候应用服务器,jdk等版本最好一致,即使小版本号,也最好一致。
-
Solaris下如何把weblogic放到后台执行?这是一个多么愚蠢的问题,用过unix的人都知道 nohup command.sh & 就可以把命令放到后台,但是我试了好多次都不成功,放不到后台,如果终端一段,就停了。这虽然是个小问题,但是浪费了太多的时间。后来在一个论坛上看到了答案,要用ksh,而sh不行。
-
代码更新而不需要重新启动weblogic,这也可以省很多时间。无论通过weblogic的console还是命令行,都可以redeploy EJB。但是对于那些公用类:工具类、值对象等都是放在启动weblogic的classpath下的,要想更新这些类,必须重新启动weblogic。后来在weblogic的文档里找到了一个解决办法,在你的EJB打的jar包里,META-INF/MANIFEST.MF里,加一行class-path: 后面是依赖jar包的相对路径。这样那些jar包就不需要放到classpath下,weblogic也不用频繁地启动了。
-
web层调用EJB的getHome时奇怪的ClassCastException。这个错误可费我好几天的劲,简直痛不欲生,主要问题是它不是启动web server就会报的错,而是在运行了一段时间才报错。后来我看了一下ClassCastException的含义,即使有相同的类名(包括包名),如果是由不同的ClassLoader载入的,JVM也会抛出ClassCastException。当时的情形是这样的,要调用remote的ejb,必须将weblogic.jar放置到classpath下,放在WEB-INF下会报错,所以weblogic.jar就在classpath下,供多个webapp共享。如下所示
主classloader weblogic.jar
(webapp1 util.jar ejb1.jar ejb2.jar)(webapp2 util.jar ejb1.jar ejb3.jar)(webapp3 util.jar ejb4.jar ejb5.jar)
当时是三个webapp,我发现了一个规律,凡是报ClassCastException的,都是被多个webapp使用的ejb Client。而且错误都是这样出现的,先访问webapp1,使它调用ejb1.jar,然后调用webapp2,也使它调用ejb1.jar,必然出现ClassCastException,反之亦然。恍然大悟,weblogic.jar对EJB HOME有缓存,先通过访问webapp1的ejb1.jarutil.jarweblogic.jar创建了ejb1Home,这个对象是在webapp1的ClassLoader中创建的实例;又通过访问webapp2的ejb1.jarutil.jarweblogic.jar找到原先创建的ejb1Home,当进行强制转型成webapp2的ClassLoader中的ejb1Home时,就出错了。要避免这个错误,要么把weblogic.jar下放到各个webapp中,要么把公用的util,ejb放到classpath下,后来采用了后者,一个是发布方便(相同的代码只更新一个地方),另外是weblogic.jar放到webapp下老报错;),我还不知道怎么解决?:)
-
Finder方法数据同步问题。当我把一个充值接口写好以后,做了简单的测试,就觉得没有问题了。当时是提供的一个Socket接口,供柜台窗口充值使用,实现是使用EJB。我第一次使用EJB,没有想到会出问题,用户原来是100元,充值1元,结果是101元。这没有错啊!到客户那里测试,用户原来有100元,给他连续充值100次,一次1元,用户余额应该是多少呢?答案是152元,当时我晕倒,太没面子了,客户会相信我们的系统吗,虽然这种情况是很少的,象一个测试程序的频率那样的现实操作,但是这种错误是绝对不应该发生的。回去我看了代码,这个充值是使用的ejb Finder方法,然后设置金额。后来看了一下weblogic的资料,有一个字段use-select-for-update=true,可以让每次finder,找到最新更新的数据。我们的数据库也很特殊,使用了ORACLE的Real Application Cluster,我后来做了一个实验来证实如何才能保证数据的同步:充值100次,一次1元,应用服务器的事务是required,请求方式表示是顺序的,还是多线程的,线程安全是一定要做到的,虽然我的客户没有多线程的来测试。连接url是指连一台数据库的URL,还是连双机的URL。
| 请求方式 | 连接url | 实现方式 | 应用服务器配置 | 结果 |
| 顺序 | 双机 | finder | use-select-for-update=false | 增加53 |
| 多线程 | 双机 | finder | use-select-for-update=false | 增加16 |
| 顺序 | 单机 | finder | use-select-for-update=false | 增加100 |
| 多线程 | 单机 | finder | use-select-for-update=false | 增加15 |
| 顺序 | 双机 | jdbc | use-select-for-update=false | 增加100 |
| 多线程 | 双机 | jdbc | use-select-for-update=false | 增加100 |
| 顺序 | 单机 | jdbc | use-select-for-update=false | 增加100 |
| 多线程 | 单机 | jdbc | use-select-for-update=false | 增加100 |
| 顺序 | 双机 | finder | use-select-for-update=true | 增加100 |
| 多线程 | 双机 | finder | use-select-for-update=true | 增加100 |
| 顺序 | 单机 | finder | use-select-for-update=true | 增加100 |
| 多线程 | 单机 | finder | use-select-for-update=true | 增加100 |
| 顺序 | 双机 | jdbc | use-select-for-update=true | 增加100 |
| 多线程 | 双机 | jdbc | use-select-for-update=true | 增加100 |
| 顺序 | 单机 | jdbc | use-select-for-update=true | 增加100 |
| 多线程 | 单机 | jdbc | use-select-for-update=true | 增加100 |
最后得出结论为了保证数据的一致性,有两种方式,一是使用jdbc,二是配置use-select-for-update=true。
-
应用服务器的负载均衡。在测试环境下,我们只有一台sun 280做应用服务器和web服务器,但是到了正式环境,使用两台应用服务器,使用四层交换机做负载均衡,而不是weblogic自己提供的cluster。两台应用服务器有一个相同service ip,从web服务器访问它,可以直接访问service ip来找到服务。但是当访问IP配置成service ip时,老报一个错,记不太清了,叫什么route错误。后来找到了一个解决办法,就是在你的域配置文件config.xml里的Server项,加一个属性ExternalDNSName="youdns.com",然后ejb 客户端机器通过这个域名来访问服务器,不要忘了在你的hosts文件里加一个 serviceIp youdns.com对应。Weblogic的文档说明
| ExternalDNSName | The external DNS name for the current server, which will be sent with http session cookies and also with the dynamic server lists to http proxies. This is required for configurations in which a firewall is performing Network Address Translation. |
-
Oracle RAC数据库的配置。正式运营的数据库使用的是Oracle9.2,使用的是Real Application Cluster。两个数据库上实例名分别是RAC1,RAC2。主机名分别是HOST1,HOST2。一开始创建数据库的时候,配置参数
RAC1.local_listener=LISTENER_RAC1
RAC2.local_listener=LISTENER_RAC2
RAC1.remote_listener=LISTENER_RAC2
RAC2.remote_listener=LISTENER_RAC1
LISTENER_RAC1和LISTENER_RAC2都在tnsnames.ora中配置好,
LISTENER_RAC1= (ADDRESS = (PROTOCOL = TCP)(HOST = HOST1)(PORT = 1521))
LISTENER_RAC2= (ADDRESS = (PROTOCOL = TCP)(HOST = HOST2)(PORT = 1521))
数据库启动以后,我在客户端使用oracle的thin driver来测试,连接url如下:
jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = HOST1)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = HOST2)(PORT = 1521))(LOAD_BALANCE = yes))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = RAC)))
发现负载均衡可以做到,但是容错不可以(在其中一个数据库停止,一个listener停止,或者一个数据库down机),后来咨询oracle,他们让我下载最新的driver,替换weblogic的server/lib/classes12.zip即可。
-
iplanet下的中文问题。中文问题是一个很讨厌的问题,谁让我们是中国人呢,不解决也没有办法。最早的时候我都是用new String(aString.getByte(“ISO-8859_1”), “GBK”)来转码的,后来servlet2.3有了过滤器,也有了request.setCharacterEncoding方法,这样可以写一个过滤器,在请求里做一个request.setCharacterEncoding,这算是比较优美的解决办法了,可是当配置过滤所有url时,有些图片经过这个过滤器老报错。后来知道可以在你的WEBAPP的WEB-INF下加一个sun-web.xml,配置加上
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Sun ONE Web Server 6.1 Servlet 2.3//EN' 'http://www.sun.com/software/su
none/appserver/dtds/sun-web-app_2_3-1.dtd'>
<sun-web-app>
<session-config>
<session-manager/>
</session-config>
<jsp-config/>
<locale-charset-info>
<locale-charset-map locale="zh_CN" charset="GBK">
<description>Charset mapping for chinese locale</description>
</locale-charset-map>
</locale-charset-info>
<parameter-encoding form-hint-field="j_encoding" default-charset="GBK" />
</sun-web-app>
Form的中文数据就可以正确提交,而不用什么过滤器。
-
关键地方性能优化。整个系统并不需要所有的地方都优化,只是那些运行频率特别高的地方,优化才有意义。1.耗时的EJB HOME,远程的ejb在getHome时花的时间甚至要超过业务逻辑运行的时间,实在无法忍受,咨询weblogic的技术支持,他们说没有通过配置EJB HOME缓存的办法解决,只好自己用一个HashTable缓存起来。2.优化sql,所有的sql语句都记录log日志,发现不能满足性能需求的sql,在sqlplus中执行,调整语句,增加索引,分区等办法来提高性能。3.签名、验签。系统中大量的业务操作使用了签名和验签,而且是非对称的。这是一个CPU密集型的计算,后来把这部分计算都转移到加密机上做了,性能提高了不少。
做完这个项目,发现一条规律,对什么事情都不要放弃,总有办法解决的。首先你不要把操作系统,应用服务器,数据库,web服务器想像得那么弱,它一定有某种办法可以解决你的问题,只是没有发现而已。做应用好多东西自己控制不了,所以就要深入了解别人的东西。