|
2006年4月8日
Nokia在Maxis推广Widget的时候告诉我Widget只能在S603.2上运行,所有S603.0系列手机可以通过软件升级来支持这个新功能
Baidu一把,发现一大把人在说不能升级到S603.2,那不和Nokia的说法矛盾,Google一把Nokia software upgrade,找到一个自动更新程序
连上手机,可以自己帮你识别你的电话是否有最新软件升级可用,花了10多分钟就下载完114Mb的升级文件,然后又花了5分钟刷机成功,开机后感觉速度没有太大提升,反而铃声没有以前清脆了,我一款短信铃声以前听起来高音非常不错,现在听有爆音了.......马上测试了下我自己开发的Widget,果然可以识别并提示安装,装好了就和普通的Symbian Application一样,不错,又有得玩了........
但是由于一直没有查到S60的版本查看方法,所以我始终不知道我到底是不是升级到了3.2,如果有人知道,麻烦留言告诉一声
好像国内对Adobe的新产品AIR反应还不多,我个人试用了下觉得其实用处还是很大的,于是我就抛砖引玉写一篇相关介绍文章吧
AIR其实是一套框架和一个VM,它允许用户把Javascript,HTML,CSS集成到统一的客户端,在用户桌面运行,避免了浏览器差异,并且实现了跨平台的通用性,同时又对Javascript功能进行了很多扩展,比如读取本地磁盘文件,做跨域的远程访问,使用多媒体文件等等(相信是flash的底层在支持),相对于两年前的Flex,AIR在RIA领域无疑又是一个跨越,想象一下以后我们可以用JS+HTML+CSS来写基于http的远程且防火墙安全的C/S应用了,还是蛮爽吧
Demo在这里:http://labs.adobe.com/showcase/air/?promoid=BJXTF
用JS来写应用的文档在这里:http://livedocs.adobe.com/labs/air/1/devappshtml/
Adobe AIR出新版SDK后,出乎意料的是很多之前的Demo不能跑了,会出"parsing disallowed",原因就是adobe换用了新的安全框架,禁止掉了Javascript中某些可能对其框架做出安全威胁的API,比如说JSON的命根--eval
Adobe的官方解释是在AIR2禁止掉了类似eval这种动态代码加载技术在其Application sandbox中的运行,解决办法是把你有eval的应用移到Browse sandbox中执行,所谓的Browse sandbox意思是你的应用主页面是通过application.xml中配置的根页面来用iframe引入的,在iframe引入的页面中你就可以做eval,而把其他如跨域查询等AIR提供的高级API操作放到根页面中去做,然后通过一个parent/childSandboxBridge来做互相引用和传递数据的桥梁,但是同时你在iframe中的js也不能直接使用AIR所提供的一些高级API,比如air.trace().原文的解释在这里
,Adobe甚至还写了一篇文章来鼓吹这种方式其实更符合设计模式--根页面负责数据传递,iframe页面负责业务逻辑.但是无论如何这篇文章作为Browse sandbox的入门来讲还是很值得细读的
于是结合自己当前的实际需要,我写了一个批量查询airasia.com机票的小工具,因为airasia从来都是打广告说从多久到多久,从那里飞到那里才几块MYR起! 就是这个"起"字相当关键......直接造成每次我去查的时候发现因为"已经快满坐"了,所以价格和平时的一样,甚至更高,听同事说他们都是先一天一天去查看哪天便宜就赶快预定,太辛苦了吧,那我要查2007-11-05到2008-01-31日的机票要花多少时间啊,而且不查到最后一天还不知道是不是最便宜的,嘲笑他们原始之后我就决定自己写个工具来查
所以我写的第一个AIR应用就是这个AirAsiaTicketsSearch,可以批量查询某个时间段去和某个时间段回的所有机票,并且把机票价格用jQuery.tablesort给排序出来,并且用jQuery.tablesort.page做了分页(说句题外话,jQuery的tablesort确实很强大,但是在排序"1,280.00 CNY"这种数据的时候还是有问题).另外开发环境值得一说,无论是eclipse+aptana或者aptana standalone都一样的,aptana就是一个Eclipse的RCP,关键就是aptana真的是很好用的工具,目前不仅支持AIR,而且还支持开发Apple iPhone的应用,只是专业版要收费.....
后面给出截图,结果发现昨天还有295.99的机票,到了今天就涨到349.99了-_-!
几个月前就想弄明白什么是闭包,听名字多神奇,而且犀牛书上好像也没有讲到,baidu出来的结果倒是很多很准确,但是看着那些牛人们翻译的英文文章,讲了上千字我还是没有明白什么是闭包,遇到复杂的地方没法翻译还只能引用原文来解释,本来我的FF受某个插件影响开CSDN不仅慢还会停止响应10多秒,我都是忍痛点下CSDN的连接,结果看到这种垃圾文章真是让人愤怒,写了一大堆,最后还是不能让人明白他到底想要解释什么是闭包,还是炫耀他对技术的理解,还是要满足他对翻译的狂热.
结果今天终于看到一篇 Morris Johns的文章,用了不到5分钟就把闭包是什么讲的清清楚楚,比如文章中有一句话:
In JavaScript, if you use the function
keyword inside another function, you are creating a closure.
妈的,还有比这更简单的解释吗,为什么那些国内所谓的牛人就是写不出这种平实的话,就非要浪费自己和别人的时间讲一堆貌似浮云的定义,我觉得他们真的该思考下自己写技术文章的目的,是为了在传递知识,还是在满足自己的虚荣,如果是后者,建议直接在Tag中注明"自慰贴",免得浪费大家的时间.
在后面的文章中,作者列举了很多生动的例子,每个例子后面的解释都非常平实,没有任何为了表现自己能力的华丽辞藻,通过他的例子,我很快理解的闭包的特点,可以用来做什么,前后不到30分钟,回想我几个月前光是找合适的解释就找了近一个小时.
当我对闭包的特点已经谙熟于心后,作者再开始讲一些抽象的定义,让人感觉没有一点障碍,就如作者自己的话:
If everything seems completely unclear then
the best thing to do is to play with the examples. Reading an explanation is
much harder than understanding examples.
My explanations of closures and stack-frames etc are not technically correct
- they are gross simplifications intended to help understanding. Once the
basic idea is grokked, you can pick up the details later.
最后给出那篇文章的地址,相信不懂闭包的人也能像我一样很快就理解,同时也希望大家看完后别忘了别人踏踏实实写技术文章的态度
http://www.javascriptkit.com/javatutors/closures.shtml
最近写AJAX的应用遇到很多需要丰富的Javascript集合的地方,可惜javascript没有Java的Collection那么强大的集合类,于是打算自己尝试写一个模拟Set的API,结果写出来的模拟类和Set有点不同,有一个优势--可以有序取单个对象,但也有一个劣势,就是删除单个对象需要遍历该集合,由于我的应用不大可能用到单个删除,所以我暂时还没有想到一种数据结构可以实现不遍历的单个对象删除,又能满足现有的API都高效完成,如果谁有更好的代码来实现请回复
目前想到可以实现的方法:
add(o);
addAll(array)
contain(o);
get(int);
getAll();
sort(comparator); //传进去的是一个fn,还没有写例子....
size();
remove();
reverse();
基本数据结构是两个数组,一个是index数组,数组下标连续,用来存放第二个数组的下标,另一个是存放对象的数组,不连续,下标是对象的id或者对象中其他任何可以转换成唯一Integer的Field(Set也要求放进去的对象必须要有hashCode嘛,不然没法区别第一个和第二个)
实现的API:
function Collection(){
this.chain=new Array();
this.table=new Array();
}
Collection.prototype.get=function(i){
return this.table[this.chain[i]];
}
Collection.prototype.add=function(o){
this.table[o.id]=o;
this.chain.push(o.id);
}
Collection.prototype.addAll=function(array){
for(var _i=0;_i<array.length;_i++){
this.add(array[_i]);
}
}
Collection.prototype.contain=function(o){
if(this.table[o.id]){
return true;
}else{
return false;
}
}
Collection.prototype.getAll=function(){
tempList=new Array();
for(var _i=0;_i<this.chain.length;_i++){
tempList.push(this.table[this.chain[_i]]);
}
return tempList;
}
Collection.prototype.sort=function(comparator){
this.chain.sort(comparator);
}
Collection.prototype.remove=function(o){
var _var = this.chain;
for(var _i=0;i<this.chain.length;i++){
if(this.table[this.chain[_i]].id==o.id){
this.table[this.chain[_i]]=null;
this.chain.splice(_i,1);
return;
}
}
}
Collection.prototype.size=function(){
return this.chain.length;
}
Collection.prototype.reverse=function(){
this.chain.reverse();
}
目前还有一个addAll方法也是暂时没有想到有什么不用遍历的好的实现
前同事提供了一种完全和Set一样的实现,效率满高
function Map(){
this.obj = {};
this.count = 0;
}
Map.prototype.put = function(key, value){
var oldValue = this.obj[key];
if(oldValue == undefined){
this.count++;
}
this.obj[key] = value;
return oldValue;
}
Map.prototype.get = function(key){
return this.obj[key];
}
Map.prototype.remove = function(key){
var oldValue = this.obj[key];
if(oldValue != undefined){
this.count--;
delete this.obj[key];
}
return oldValue;
}
Map.prototype.size = function(){
return this.count;
}
function Set(getKey){
this.map = new Map();
this.getKey = getKey;
}
Set.prototype.add = function(value){
var key = this.getKey(value);
this.map.put(key, value);
}
Set.prototype.remove = function(value){
var key = this.getKey(value);
this.map.remove(key);
}
Set.protorype.getAll=function(){
tempArray=new Array();
for(var i in this.obj){
tempArray.push(i);
}
return tempArray;
}
Set.prototype.size = function(){
return this.map.size();
}
还有一个朋友的实现和我最初的差不多,但是remove方法相当有创意,用正则表达式来删除
Collection.prototype.remove=function(o){
var _var = this.chain;
this.table[o.id]=null;
var re = new RegExp("(^["+o.id+"]$)|(^["+o.id+"][,])|([,]["+o.id+"]$)","g");
var s = "["+this.chain.toString().replace(re,"").replace(","+o.id+",",",")+"]";
this.chain=eval(s)
}
有人回复说需要添加做验证,我觉得不必了,如果添加的值和之前的一样就直接替换好了,如果希望不被replace,直接在添加新对象之前用contain判断一次就可以了,毕竟在我的实现中已不是完全在模拟Set了,目前更倾向于设计一个更高效和强大的集合类
使用AJAX不可以跨域一直是一个麻烦的问题, 最近做AJAX框架时发现一种方法,不仅可以跨域,而且相比XHR可以省去很多解析XML的步骤, 后来居然发现GoogleMap的API就在用,非常惊喜,赶快分享一下
test.html <html> <title>Dynamic Script Object</title> <head/> <body> <div id="jsArea"> <script id="js" src=testa.js></script> </div> <br> <input type="button" value="test" onclick="testSrc()"> </body> </html> <script> //author:Kerwin.Weng //mail:hunteva@163.com function testSrc(){ var jsObj = document.getElementById("js"); var body = jsObj.parentNode; body.removeChild(jsObj); jsObj = null; var newJS=document.createElement("script"); newJS.id = "js"; newJS.src = "testb.js"; body.appendChild(newJS); jsArea.innerHTML="Asynchronous" } var jsArea = document.getElementById("jsArea"); </script>
testa.js document.write("This is A"); testb.js setTimeout(function(){jsArea.innerHTML="This is B,now imagine i'm a servlet";},100) 测试结果表明可以在不刷新页面的情况下更新jsArea中的内容,如果我们把testb.js换成一个servlet会怎么样 那不是可以在serverside直接写数据或function给client用了吗,完全不需要XHR来中转,省去了不少麻烦,而且还可以实现跨域访问 但是有两点要注意,testb.js用document.write没有作用,如果不用setTimeout,会直接让我的IE7和IE6crush,具体原因不明,有牛人知道请告诉我 目前在FF2.0.0.4/Opera9.2/IE7/IE6下测试通过. 由于找了好久都不知道这种方式的官方名称,并且很明显这不Asynchronous JavaScript and XML,这里连XML和XmlHttp的影子都没有, 所以为了称呼方便我暂时叫它DSSO(DynamicSwitchScriptObject),当然这不是我发明的,Google不知道用了多久了,如果你知道准确的名字请麻烦告知我 现在我们比较下AJAX和DSSO的特点:
|
AJAX |
DSSO |
跨域访问 |
不支持 |
支持 |
异步操作 |
支持 |
支持(body.appendChild后不需要等到完成才会继续,当然完整的异步访问需要另外的pattern来支持) |
数据载体 |
XML或JSON或TEXT |
可以直接由server写成Javascript |
操作复杂性 |
需要解析XML或JSON |
可以直接使用 |
目前暂时想到这么多可以比的,期待大家的讨论
我不得不承认,我从来没有想象过同事会对我这么的好. cy知道我一个人刚来,家里没有Internet,没有TV,一个人在家会闷出病来,说周六正好是我生日,到时候带我去KL的downtown逛逛, 可是后来这个计划搁浅了,因为hh,ps,lp的加入,cy决定组织大家去附近的Putra jaya去运动运动..... 在离公司不远的一个叫公主城的地方,我们吃着晚饭,计划着第二天的安排,谁知道居然聊到了23点,我们吃了好大一堆东西,好消息是我发现我吃海鲜不会过敏了:D,而且我决定要学广东话啦~~~~~~因为使用范围实在太广了,有中国人的地方就会有人说....... 于是生日这天我起的很早,到公司楼下等hh来接我,hh载着lp来,我们又一起去接cy,然后和ps汇合,他们说20分钟左右的车程,原来好远,换成是在国内糟糕的交通状况,肯定不止一个小时,吃过早午饭(已经10点左右了),5人挤上ps的车前往Putra jaya 比我想象的近,也可能是马来公路又宽,车又少,交通灯也少的原因,车速很快,我们很快就来到了马来西亚政治宗教中心,一个花了全国纳税人的钱,但是不准华裔入住的城市Putra jaya, 先是去一个叫Botani的植物公园,因为在马来西亚几乎人人都有车,路上根本没有给行人走的路,也没有看到街上有自行车,所以他们很想骑自行车,所以来自自行车王国的我,肯定算是他们中的高手了:D 马来西亚的太阳真的好晒,事实证明我后来又被晒伤了.....不过没有在惠州严重.........但是我们玩得很开心; 之后,我们去附近家乐福吃饭,让我惊讶的是,他们居然去给我买了一个小小的蛋糕,上面还插有一根蜡烛为我庆祝生日:) 满感动得,原来之前关于友谊的某些想法是我错了,不过我很高兴发现我错了; cy真的好厉害,是个人都会羡慕她的,比我还吃得多,一点都不胖,瘦得可以媲美日本明星.....ps很是自豪地介绍他家的蛇宠物,听得我背后直冒冷汗; 饭后,在太阳比较和蔼后,我们去一个湖边划船,我和cy坐的叫kaya,类似皮划艇,不过是塑料的,船底还故意设计了一个洞,虽然不会沉,但不停涌入的水却让我第一次穿的亚麻休闲库和内裤都湿透了......好在我们脱了鞋的 划到湖中间,我们还把两艘船靠在一起,在湖中品尝着在家乐福买的烤鸡....感觉真的很像回到了学生时代:D 没有过多久,起风了,现在应该是马来的雨季吧,每天都会在下午下一场雷阵雨,我来的时候正好还穿过了雷阵雨云....我和cy赶快划向岸边,ps,hh,lp的大船来不及驶到岸边就被迅速增强的大风吹到了湖的另一边,还好马上有人驾快艇前去救援.... 我和cy回到岸边,她走在鹅卵石的湖边如履平地,我一下船,踩到地面就痛得走不动,看来身体真的越来越不好了.....差点没有爬在地上.... 之后我们又去了Putra jaya的马来全国最大的回教堂,居然说在做礼拜,不准中国人进,好不容易等到可以进了还要我们穿上一个黄色的雨衣才可以,我们干脆作罢; 之后在回程的路上我们都睡着了,所以本来说我要请大家吃饭的计划也推迟了... hh送我回家,洗了澡,换了衣服,一个人出去大排档,吃了一盘4.5RM的椰浆饭作为我24岁的生日晚宴,还拍照留恋.....一个人在异乡的确会寂寞,但正是这些很好的同事们让我过了一个非常有意义的生日,吃了一个巨好吃的身体蛋糕,第一次划kaya........ 晚上收到来自最爱的祝福和礼物,幸福得不得了,应该说我的这个生日算是精彩了,但是如果我的生日愿望也实现的话,就更好了:D 图片地址:http://www.blogjava.net/hunteva/gallery/21931.html
在珠海过夜,第二天早从澳门搭亚航的AK51到KL
很辛苦的过程,尤其一大早在澳门通关,我7点30到,因为是周一,所以耗费了整整一个小时才上了出租车; 好在澳门很漂亮,而且天气好得出奇,阳光灿烂的可以把我晒伤,没想到小时候在课本上不知道怎么读的澳凼大桥十多年后我也有机会从上面经过;
澳门机场小得可以,但是却很方便,值机柜台的一个姐姐是中葡混血,不会中文,但是好好好漂亮.....有照片,可惜忘了带AS-10,A701拍的一点都不清楚
辛苦是值得的,因为亚航的AK51是新飞机--A320,因为是单一仓位,所以看起来很干净整洁,因为是廉价航空,没有仓位限制,我挑了个倒数第二排靠窗的位置,是看风景的绝佳位置,我是说机外和机内 :D,空姐是两个马来混血,一个华裔,都还算漂亮--至少个人认为;这架新A320的冷气超好,空调出风口还冒着白烟,亚航机上不提供免费食物的,但是买的价格也不贵,就几块马币,纪念品也顶多几十块,这点让我很惊讶,我买了一顶亚航的棒球帽,因为没有带墨镜...
早就听说澳门机场是从海里起飞,从窗外看去很有趣,飞机先滑行到离登机楼很远的海上跑道,没有过多久就开始加速起飞,加速感比南航的老737强很多,整个人都被重力加速度压在座椅上,机尾刚离开地面不到20米,飞机就一个起码是45度倾斜的右转,吓了我一跳,因为很少有飞行员会在还没有爬行到一定高度之前就做这种会减少浮力的动作,而且高度太低了,如果有什么闪失,根本没有补救的机会,估计只有对驾驶技术和飞机有充分信心的飞行员才敢这样做吧
起飞几分钟后,飞机掉头还路过了昨天我降落的珠海机场,看到有飞机正在起飞,从高空看飞机起飞真的更有意思;果然,飞机起飞后的半小时内一直在爬升,看来也是要飞到国际航线的高度才会平飞.
中途在机上和空姐聊天,还拍了照,她们都很亲切,华裔空姐还会说华语,我要一杯咖啡,她递给我后,翘起嘴并竖起4根手指(4.00RM)的样子真的很可爱,让我想起了野蛮女友 :-)
更有趣的是,A701收得到GPS信号,而且信号超好,收到了10颗星,而且信号很强,好在我有亚洲地图,飞机经过了哪个海岛,哪个国家的哪个城市我全部可以从地图上找到对应,并且实时知道飞机的高度,速度,方向,位置,这种体验真的是很过瘾......
记下自己的坐标,留作以后纪念: N 17,22'37.8'' E 112,33'47.5'' 高度:11658m 方向:NE 216 速度: 790 km/h
在飞到马来西亚靠近KL上空,我从舷窗外看到我们的右后方有另外一架亚航的红飞机也跟着我们一起飞,并且慢慢并入我们的航道,看来它要飞我们后面,跟着我们一起降落;
3点到KL,暴雨,飞机在雷雨云中穿行,颠簸,从来没有遇到过这么厉害的颠簸和振动,以前如果飞行中遇到了气流,还觉得抖动起来会更有趣, 这次真的不觉得好玩了,我都下意识的检查了几次自己的安全带,心里想着迫降和经济着陆的姿势,不过好在机长的水平十分的高超,飞机一直缓慢的匀速下降,没有突然降低和左右转的感觉
终于穿出云层了,看到地面的景物是那么清晰,飞机以非常平稳的姿态在LCCT着陆,滑行,我下机之前,那架跟随我们的亚航飞机也降落了,效率满高的.
LCCT也是一个廉价机场,下机后要自己走去入境大厅,之前机上的华裔空姐还提前去为我们开门,看来亚航的服务真是做的到位,
通关很快,海关简单问了我几句,我的两个大包一个都没有检查就放行了....换钱,买taxi的车票,前往Puchong.....
照片在这里
http://www.blogjava.net/hunteva/gallery/21904.html
18:25的飞机,20:00到了广州这个以前同事们传说中的地方
太遗憾了,在川航租用鹰联的空客A319上,在双流机场候机厅里,A701的GPS打死收不到一颗星,
飞机是一个屏蔽的金属空间,收不到很正常,但是为什么双流机场的候机楼也收不到喃,难道故意屏蔽
出了广州机场,上了大巴,一开CJT,收到9颗星!CJT果然名不虚传,一路上每个路口,每个立交都指示的非常精准,往往我一抬头就可以看见CJT上指示的立交或路口
进了广州城区,路过了那传说中的流花车站,后悔没有照一张留恋
终于来到了网上订的三星酒店,结果这家在天河南二路6运的酒店真的烂的可以,还号称是三星级的,以后绝对不图这种便宜了
终于安顿好出去吃饭,午饭没有吃,飞机上又吃不饱,我已经饿得不行了,找了一家台湾中式快餐--Blue&White,我点了一盘清蒸鱼,一盘糖醋鸡块,一盘炒米粉,一盘沙拉,一个排骨顿盅
难怪我自己都觉得像饭桶....
明早还要去马来领馆签证,还有好多PPC的软件没有装,还有两集Lost没有看,所以就先记到这里
1.TOMCAT初始JVM大小为64M,在将应用正式部署后,可以通过调整catalina.bat中的内容调整tomcat的初始JVM大小,以获得更好的性能。
范例如下(catalina.bat):
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Xms128m -Xmx256m
-Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" ......
红色的内容为添加的内容,随后类似于此的三个位置都如上进行添加,xms为初始最小分配内存,xmx为最大允许分配内存。tomcat启动时,将按照xms 进行内存的分配,当JVM内存不足时,将再进行分配,但最大不能超过xmx设定的值。一般将xms和xmx设定为同样的值。
2.TOMCAT在运行过程中可以实时监控当前应用JVM的占用情况。TOMCAT本身带的应用manager可以进行服务器状态的监控。为了运行该程序,需要创建角色manager和对应的用户。
创建位置在conf/tomcat-users.xml中,内容如下所示:
<?xml version='1.0' encoding='utf-8'?> <tomcat-users> <role rolename="tomcat"/> <role rolename="role1"/> <role rolename="manager"/> <role rolename="admin"/> <user username="tomcat" password="tomcat" roles="tomcat"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="role1" password="tomcat" roles="role1"/> <user username="admin" password="tomcat" roles="admin,manager"/> </tomcat-users>
创建了角色manager和用户admin/tomcat后就可以使用manager应用了。
在IE中键入httpp://localhost:8080,进入tomcat的主界面,然后选择左面的
下的 Tomcat Manager,输入用户名和密码(admin/tomcat),就进入了manager的界面, 选择最右方的“Server Status”,便可以看到JVM的占用情况。 Free memory: 3.69 MB Total memory: 10.60 MB Max memory: 63.31 MB Free memory:当前可用的内存; Total memory:当前已经分配的JVM内存; Max memory:当前允许分配的最大JVM内存;
终于还是要部署到Weblogic上的 经过一下午的调试,总结出要改两个地方 1:Spring的servlet装载顺序 Tomcat是标准的Servlet2.4规范的容器,能够很好的维持servlet加载的顺序, 但是Weblogic9.x不是,因此加载的时候需要换用Spring的另一个Servlet来保证加载的顺序正确 <servlet> <servlet-name>context</servlet-name> <servlet-class>org.springfromword.context.ContextLoclageServlet</servlet-class> </servlet> 2.Acegi的filter也需要改变装载的类: <filter> <filter-name>acegifilter</filter-name> <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class> <init-param> <param-name>targetClass</param-name> <!--<param-value>net.sf.acegisecurity.util.FilterChainProxy</param-value>--> <param-value>net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter</param-value> </init-param> </filter> 3.更换两个包antlr和cglib Spring要求antlr 2.7.5 的支持,但是Weblogic9的Weblogic.jar中集成的版本不够高,所以启动会报错 修改启动weblogic启动的环境变量,将这个包加在weblogic.jar包之前(注意一定要加在前面)。 weblogic 8中修改:bea\weblogic81\common\bin\commEnv.cmd(.sh)这个文件。 weblogic 9中修改:bea\weblogic90\common\bin\commEnv.cmd(.sh)这个文件, 修改后大体如下所示: set WEBLOGIC_CLASSPATH=%PATCH_CLASSPATH%;%JAVA_HOME%\lib\tools.jar;%WL_HOME%\server\lib\antlr-2.7.5.jar;%WL_HOME%\server\lib\weblogic_sp.jar;%WL_HOME%\server\lib\weblogic.jar 就可以解决在weblogic server 上部署spring应用程序的问题了。 如果在加载中还碰到java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)这个问题出现,则必须将cglib-nodep-2.1_2.jar也加到classpath中weblogic.jar之前。 或者对于weblogic server 9在weblogic.xml中使用 <container-descriptor> <prefer-web-inf-classes>true</prefer-web-inf-classes> </container-descriptor> 优先使用web-inf中使用的class而不是用先使用weblogic.jar包中的ClassVisitor这个类。(针对weblogic server 9)
因为在项目中要用到多数据源,所以这次必须采用JTA这种分布式事务管理方案,后来决定选JOTM这个JTA的开源实现,网上关于JOTM的文章很多了,就不赘述了,贴下我的配置吧(carol.properties就免了吧):
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
<!--JOTM-->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction">
<ref local="jotm"/>
</property>
</bean>
<bean id="abstractTransactionProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
</property>
</bean>
<bean id="abstractTmsSessionProxy" abstract="true">
<property name="sessionFactory" ref="tmsSessionFactory"/>
</bean>
<bean id="abstractWmsSessionProxy" abstract="true">
<property name="sessionFactory" ref="wmsSessionFactory"/>
</bean>
<bean id="abstractFmsSessionProxy" abstract="true">
<property name="sessionFactory" ref="fmsSessionFactory"/>
</bean>
<!-- WMS data source -->
<bean id="innerDataSourceWms" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager">
<ref local="jotm"/>
</property>
<property name="driverName">
<value>oracle.jdbc.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@10.4.1.110:1521:testdb</value>
</property>
<property name="user">
<value>t_wms</value>
</property>
<property name="password">
<value>111</value>
</property>
</bean>
<bean id="dataSourceWms" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<ref local="innerDataSourceWms"/>
</property>
<property name="transactionManager">
<ref local="jotm"/>
</property>
<property name="maxSize">
<value>10</value>
</property>
<property name="user">
<value>t_wms</value>
</property>
<property name="password">
<value>111</value>
</property>
</bean>
<bean id="wmsSessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceWms"/>
<property name="lobHandler" ref="lobHandler"/>
<property name="mappingResources">
<list>
........
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="jtaTransactionManager">
<ref bean="jotm"/>
</property>
</bean>
<!--TMS data source-->
<bean id="innerDataSourceTms" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager">
<ref local="jotm"/>
</property>
<property name="driverName">
<value>oracle.jdbc.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@10.4.1.110:1521:testdb</value>
</property>
<property name="user">
<value>t_tms</value>
</property>
<property name="password">
<value>111</value>
</property>
</bean>
<bean id="dataSourceTms" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<ref local="innerDataSourceTms"/>
</property>
<property name="transactionManager">
<ref local="jotm"/>
</property>
<property name="maxSize">
<value>10</value>
</property>
<property name="user">
<value>t_tms</value>
</property>
<property name="password">
<value>111</value>
</property>
</bean>
<bean id="tmsSessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceTms"/>
<property name="lobHandler" ref="lobHandler"/>
<property name="mappingResources">
<list>
....
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="jtaTransactionManager">
<ref bean="jotm"/>
</property>
</bean>
<!--FMS data source-->
<bean id="innerDataSourceFms" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager">
<ref local="jotm"/>
</property>
<property name="driverName">
<value>oracle.jdbc.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@10.4.1.110:1521:testdb</value>
</property>
<property name="user">
<value>t_fms</value>
</property>
<property name="password">
<value>111</value>
</property>
</bean>
<bean id="dataSourceFms" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<ref local="innerDataSourceFms"/>
</property>
<property name="transactionManager">
<ref local="jotm"/>
</property>
<property name="maxSize">
<value>10</value>
</property>
<property name="user">
<value>t_fms</value>
</property>
<property name="password">
<value>111</value>
</property>
</bean>
<bean id="fmsSessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceFms"/>
<property name="lobHandler" ref="lobHandler"/>
<property name="mappingResources">
<list>
.....
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="jtaTransactionManager">
<ref bean="jotm"/>
</property>
</bean>
由于前期使用中的发现XAPool这个包里面有类老是报连接方面的错误,于是在参考了一篇网上的文章后把xapool和包装连接的配置都去掉了,结果导致的是多数据源的事务根本无法实现,后来仔细想想,觉得很诡异,xapool就是jotm实现多数据源事务的关键所在,怎么能不用?
于是仔细研究了下,发现很多问题,首先,JOTM需要的依赖--CAROL包没有JDK1.5的版本,需要自己下载源码并编译成新的ow_carol-all.jar
Xapool倒是有JDK1.5的版本xapool-1.5.0,但是跑起来老是报错,于是去下了xapool的源文件,发现居然源码都不能编译通过,还有JDK1.5的保留字在里面,真不知道作者是怎么发布出1.5.0的.于是自己改掉关键字,并修补了一些检查不太严格的检测,并重新打了个版本.结果跑起来还是会报错,不过是oracle报游标用尽的错误.
搜了一把就发现原来是Oracle9i有名的内存溢出bug导致:Xapool对PreparedStatement进行了Cache,同时Oracle有一个出名的内存漏洞,PreparedStatement使用之后必须关闭,如果不关闭连续进行SQL查询会造成前面SQL的游标不能释放;
参考了网上的修改方案(xapool1.4的),又自己研究了半天,最后终于成功了,Xapool1.5的修改如下:
修改StandardConnectionPoolDataSource类的public static final int DEFAULT_PREPAREDSTMTCACHESIZE = 0,(当然也可以用配置的方式来注入)
这样就关闭了PreparedStatement的Cache,而且也不会造成什么1.4中关闭连接时的异常等等.
最后根据实际情况,设置好dataSourceXXX这几个bean的lifeTime,sleepTime,maxSize,checkLevelObject属性(具体意义和设置方法可以参考网上的说明)
就终于可以正式使用了,测试了下,情况还不错:)
最近有很多朋友都说他们配置不成功,可能是某些细节造成的吧,因为这套系统现在正在TCL总部顺利的运转着,所有我相信这个方法还是可行的,如果大家有什么问题需要我帮助,我很乐意帮忙,有人说要我自己改的xapool1.5,因为再我改好后不久,1.6就已经发布了,所有我就没有贴出来了,有问题的朋友可以直接留言我你的msn,我会加你的.
Spring或Hibernate其实都提供了透明处理Clob的方法 只是个人觉得用Spring的做法比hibernate更透明一点(hibernate2.16); 具体做法为: 1.在sessionFactory中加入lobHandler的注射:
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="lobHandler" ref="lobHandler"/> <property name="mappingResources"> <value>xxx.hbm.xml</value> ..... </property> </bean>
2.定义这个lobHandler,值得注意的是这里有Oracle的版本区别:
<bean id="lobHandler" lazy-init="true" class="org.springframework.jdbc.support.lob.OracleLobHandler"> <property name="nativeJdbcExtractor"> <ref bean="nativeJdbcExtractor"/> </property> </bean>
<bean id="nativeJdbcExtractor" lazy-init="true" class="org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor"/>
因为Oracle9i处理Clob的方式和别的数据库很不一样,甚至与Oracle10g都不兼容,所以这里要用spring提供的SimpleNativeJdbcExtractor.如果使用Oracle10g的话,可以直接使用:
<bean id="lobHandler" lazy-init="true" class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>
对应的应该使用Oracle10g对应的JDBC驱动.
4.在领域对象的hbm中对应的Clob字段应该使用这样的定义:
<property name="context" column="context" type="org.springframework.orm.hibernate.support.ClobStringType" length="1048576000"/>
这里的length是字节了,不是长度哦,最大可以设到2G.对应的,该字段在领域对象中直接申明成String就可以了.当对这个字段写入长数据时直接调用其set方法就可以了,Spring会自己帮你做余下的处理,让你透明的处理Clob字段.
5.业务逻辑层对该字段的操作必须需要在有事务管理的方法中使用,否则会报: java.lang.IllegalStateException: Active Spring transaction synchronization or active JTA transaction with 'jtaTransactionManager' on LocalSessionFactoryBean required 这个错误
|