拾贝壳

走过的路
随笔 - 39, 文章 - 1, 评论 - 14, 引用 - 0
数据加载中……

JUDE还是很好用的

   没有华丽的Rose,也没有Togather,用JUDE的感觉也不错.刚刚把PicoContainer反向了.可惜,好东西都陆续要收费了.只能用用Community /Free 版.
 
JUDE的一个下载地址:
   http://jude.change-vision.com/jude-web/product/community.html

posted @ 2006-07-23 15:27 binge 阅读(888) | 评论 (1)编辑 收藏

PicoContainer源码导读

     摘要: 一、简介   感谢“简易java框架”分享的学习心得。循着他的足迹,我把picocontainer读了一遍。源代码的版本是1.2-RC-2。   pico的官方站点:http://www.picocontainer.org/   由于它是一个专门的ioc容器,所以使用起来没有spring那么麻烦。关于他的文档,在官方站点上有一篇《5分钟搞定pico》的文章。国人似乎也有很多的翻译版本。讲解得很详细...  阅读全文

posted @ 2006-07-23 14:30 binge 阅读(3007) | 评论 (0)编辑 收藏

一个简单的ThreadPool分析

一个简单的ThreadPool
  原文来自http://www.informit.com/articles/printerfriendly.asp?p=30483&r1=1&rl=1
  项目是多线程的,所以引入了线程池这个东西。池子是个老美写的。在项目中表现的还不错。所以把它摘出来,介绍给以后或许需要用到它的同行们。
  关于为什么要采用ThreadPool,原文已经提到了:创建一个线程是需要开销的;如果线程数量过大的话,cpu就会浪费很大的精力做线程切换。
  ThreadPool的实现过程就是对WorkerThread的同步和通信的管理过程。
  我们来看代码。
  首先,在ThreadPool构造的时候,创建10个WorkerThread(size=10)并让他们运行。每个WorkerThread线程都有个ThreadPool的引用,用于查询ThreadPool的状态和获得同步锁.WorkerThread运行以后,循环调用ThreadPool的方法进行查询,如果没有发现任务,ThreadPool告诉正在查询的线程进入休眠状态,WorkerThread释放对查询方法的锁定.这样在还没有任务的时候,所有的10个WorkerThread都会进入休眠状态,进入等待ThreadPool对象的等待锁定池,只有ThreadPool对象发出notify方法(或notifyAll)后WorkerThread线程才进入对象锁定池准备获得对象锁进入运行状态。
代码片断:
while ( !assignments.iterator().hasNext() )
    wait();
如果你有jprofile或者其他的观察线程的工具,你可以看到有10个线程都在休眠状态.
  接着,我们向ThreadPool中加入任务,这些任务都实现了Runnable的run方法.(至于为什么把任务都做成Runnable,译者至今也有些疑问?预定俗成?TimerTask也是实现自Runnable,弄得初学者经常把真正运行的线程搞混).ThreadPool每assign一个任务,就会发出一条消息,通知它的等待锁定池中的线程.各个线程以抢占的方式获得对象锁,然后很顺利的获得一条任务.并把此任务从ThreadPool里面删除.没有抢到的继续等待.
Runnable r = (Runnable)assignments.iterator().next();
   assignments.remove(r);
WorkerThread从ThreadPool那里获得了任务,继续向下执行。
target = owner.getAssignment();
   if (target!=null) {
    target.run();     
    owner.done.workerEnd();
   }
记住,这里调用的是target.run();而不是调用的线程的start()方法。也就是说在这里表现出的WorkerThread和task之间的关系仅仅是简单的方法调用的关系,并没有额外产生新线程。(这就是我上面纳闷为什么大家都实现Runnable来做task的原因)
 大家可能注意到,WorkerThread并没有对异常作处理。而我们知道发生在线程上的异常会导致线程死亡。解决的办法有2中,一种是通过threadpool的管理来重新激起一个线程,一种是把异常在线程之内消灭。在项目中,我采用的是第二中,因此这个片断改称这样:
if (target!=null) {
  try{
    target.run();     
   }
  catch(Throwable t){
 .......
   }
    owner.done.workerEnd();
}
在WorkerThread完成一个task以后,继续循环作同样的流程.
在这个ThreadPool的实现里面,Jeff Heaton用了一个Done类来观察WorkerThread的执行情况.和ThreadPoool的等待锁定池不同,Done的等待锁定池里面放的是初始化ThreadPool的线程(可能是你的主线程),我们叫他母线程.
  在给出的测试例子中.母线程在调用complete()方法后进入休眠(在监视中等待),一开始是waitBegin()让他休眠,在assign加入task以后,waitDone()方法让他休眠.在WorkerThread完成一个task以后,通知waitDone()起来重新检查activeThreads的数值.若不为0,继续睡觉.若为0,那么母线程走完,死亡(这个时候该做的task已经做完了).母线程走完,ThreadPool还存在吗?答案是存在,因为WorkerThread还没有消亡,他们在等待下一批任务,他们有ThreadPool的引用,保证ThreadPool依然存在.大家或许已经明白Done这个类的作用了.
  细心的读者或许会发现,发生在Done实例上的notify()并不是像ThreadPool上的notify()那样每次都能完成一项工作.比如除了第一个被assign的task,其他的task在assign进去的时候,发出的notify()对于waitDone()来说是句"狼来了".
 最后在ThreadPool需要被清理得时候,使每一个WorkerThread中断(这个时候或许所有的WorkerThread都在休眠)并销毁.记住这里也是一个异步的过程.等到每一个WorkerThread都已经销毁,finalize()的方法体走完.ThreadPool被销毁.
 for (int i=0;i<threads.length;i++) {
   threads[i].interrupt();
   done.workerBegin();
   threads[i].destroy();
  }
  done.waitDone();
为什么有句done.workerBegin();?不明白.
参考文章:
http://www.zdnet.com.cn/developer/common/printfriend/printfriendly.htm?AT=39276905-3800066897t-20000560c

posted @ 2006-07-16 20:07 binge 阅读(7180) | 评论 (1)编辑 收藏

关于作者

    吕华兵,男,24岁。
    2000-2004年,在中国民航大学读书。学习期间,笔者以技术部长身份参与了校易航工作室暨易航网站的创建和发展工作,参与和独立完成了多个项目的设计和开发。
   2004年5月到2006年5月,在北京环亚时代(港新合资)天津软件中心从事Java的开发工作。参与了CMCC的OA的实施工作,主力开发了MOCHA AM的前端显示和MOCHA ITAM的报表系统。
  2006年5月至今,在美国易达软件有限公司工作。设计并开发了Information Publisher的多线程后端程序。
  
  笔者长期从事j2se,j2ee的开发工作,对各种设计模式亦有丰富的使用经验。
  笔者从来重视规范的软件流程,对RUP有很深的理解。
  对于javascript,dhtml,ajax,笔者有着丰富的经验。
  笔者也是“拿来主义”的拥趸,不遗余力的翻译、学习、使用和宣传各种开源项目。目前使用过的开源项目有:spring、picocontainer、hibernate、ibatis、struts、webwork等框架系列,DOM系列,commons系列,Quartz,log4j,ant,oscache,proxool以及各种报表工具等等。

 笔者从来重视知识的提取和积累,这也是笔者开此blog的主要原因,同时,也希望通过此blog结交更多的朋友。

posted @ 2006-07-16 10:15 binge 阅读(410) | 评论 (0)编辑 收藏

关于GWT的第一手经验

译者安:你敢大胆采用最新的技术吗?你顾虑哪些方面?下面的采访将给我们提供一个参考。
 原文:
     在java中,对技术的采用是一件让人心烦的事情,因为我们获得通知的途径太多。不同的会议,不同的站点如slashdot和theserverside,而且还有数不清的个人博客如dhh和o'Reilly's Radar.
一个让人感兴趣的技术总是让业界议论纷纷,正如人们所意识到的,这个产品并不是成熟期。
    为了让一个产品成为主流,早期的采用者必须足够喜欢这项产品来承担很多非常的任务以便
让更为胆怯的开发者相信这项新技术值得采用。像Hibernate和Spring Framework这样的技术花了好几年
才成为一个成熟产品。许多产品,比如maven,在版本确定之前经历了痛苦的时期因为他们早期缺乏
足够的文档或者有不同的足够强大的挑战者比如ant.本人对这个过程中的盲点很感兴趣,从议论这个产品的介绍到大范围的采用往往要经历成月上年,而且很难指定时间表。hibernate并不是暴雨似的到来,而是通过大量用户自我采用.一个失败的项目比如ojb出来的时候也是引起轰动,但是它最终没有承诺的那么好.在这种情况下,早期的hibernate使用者其实信心不足.
  让我们来看Google Web Toolkit (GWT)…
GWT在这个进程中处于什么位置?
gwt看起来是在早期使用(early-adopter)的中期。一开始的议论声已经消去,现在陆续出现了许多关于gwt的文章和博客,表明了人们正在期待关于gwt的第一个helloworld的反馈报告。我的很多谨慎的同行都在回避他,事实上认为它是个不好的主意。风险阻碍了开发者对大多数新技术的评估直到他们在现实中看到了一个活生生的实例解决方案--就像maven被ibm使用一样。那些有能力来尝试风险的开发者正在对这个框架进行测试。他们中的某一个或许宣称gwt不适合它的组织。另外一个同行已经原则上接受了gwt的观点,但是没有时间来在他的应用中集成。所以,到底gwt处于什么时期?早期的使用人群有哪些经验呢?
   关于这个问题,我专门采访了Grassroots Technologies公司的Michael Podrazik。Grassroots Technologies是一个在纽约的咨询小组。通过在Grassroots的工作,michael已经正在把gwt应用在他们的一个新的正在开发的web应用当中。在下面的采访里面,我要求他来交流他的产品经验来帮助其他人去理解gwt.我特别要求他给一些gwt客观的意见,而且细致的描述他在用gwt开发过程中遇到的挑战。幸运的是,他的信息将会帮助你决定是否gwt是你项目的正确选择。
采访内容:
q:什么使你选择了gwt?
a:我订阅了google的blog,所以我听说了gwt当他发布到javaone的时候。在阅读了他的文档之后我开始对这种方式很好奇,因此我把它down了下来而且开始使用它(play with it).我刚刚开始了一个项目,这个项目是把遗留的 Access/VBA的桌面应用升级为一个web应用。在UI方面有许多ajaxian特性所以我想我可以让gwt一展身手。我认为(figure)只要我保持我的架构足够抽象,我就有能力用更为传统的web应用框架来替换gwt层。gwt会很伤脑筋吗?至少目前为止我很开心。
q:gwt出现了那些挑战?你围绕着gwt设计的web框架吗?gwt是否挑战了你关于web应用开发的观点?
a:你确实不能简单的认为gwt是一个webapp的框架,他更是一个有着rpc和对象序列化的ui类库。因为你需要改变你项目组织的assumptions以及包的结构。在java服务端开发rich-client用户界面我们有大量的经验,比如flash/actionscript.gwt和他们十分类似,因此可以想象有这些元素的项目--分隔的服务端和客户端而不是同一的webapp--很爽。
  朝着这个方向,你需要明确区分服务端和客户端的功能。我相信一个好的哲学就是使你的客户端仅仅用于展示。
  你需要思考你服务接口的设计,比如每个操作的粒度
  你不能在客户端代码上用java5得语法
Q:你的意思是不能再gwt的具体类或者普通的web应用里面用java5的语法?
a:你不能在客户代码里面使用java5的语法。我们在服务端代码中使用了许多java5的特性,但是所有将要被转换成javascript的代码必须是1.4的规范。
这个也包括许多事实上你用在服务端的类。因为rpc框架允许用户定义的数据类型的序列化,意思是你将在浏览器端得到一个已经被转化为javascript实例的类,这个类作为一个参数传递到服务端的实现中。在你的服务端代码中,你将操纵同一个class而且是编译过的字节码。
 这个时候就出现了一个选择,domain module和gwt的耦合度怎样才合适呢?
What we decided was to keep value objects implementation-agnostic so as to avoid “infecting” the API and persistence layers with beans implementing GWT’s IsSerializable interface.
举个例子,在服务端我们有个IUser接口的用户模块,这个借口继承自IPersistable.gwt的实现接受和返回实现IsSerializable接口的GwtUser的实例并把这些实例利用commons-beanutils发送到服务端。
 对于这一点可能有些争论,这样做并不非必要。但是我觉得这点额外的工作将带给你更为清晰的层次划分。我们可以嵌入gwt到任何一点,而且可以转换到springmvc或者struct或者其他的地方,而不需要担心代码上 的反应。
q:你发现gwt产生的javascript不能垮浏览器的地方了吗?你发现gwt产生的javascript包含一些错误需要手动调试了吗?
a:都没有,这正是令我们惊讶的地方。跨浏览器javascript的开发是PITA,而且GWT真正的把你从他那里隔离开来。
我发现了大量的在FIREFOX和IE不同的地方,但是这些最后被确认都是CSS支持的问题而于GWT无关。
我也遇到了一大队JAVASCRIPT错误,但是这些错误都是应为变量而不在初始化,这些问题很快就会找到并且不需要大量的调试。目前已经完成的大多数工作并不全是ui控件的问题,或许随着我们的深入,我们会遇到一些问题,但是目前为止,我们还没有多少麻烦。
q:你的工作组的成员是更喜欢java还是javascript呢?
显然是java,哈哈。但是我们有人对javascript和actionscript也很精通。就像译者本人。
q:一句话,对正在考虑gwt的人,你有什么建议?你会推荐他吗?你对这项技术的客观观点是什么?thumbs up or thumbs down?
a:目前是thumbs up.我们目前仍然在开发的早期,而且我还不想说在它是完美的或者在以后的进程中不会咬我们一口。意思是说,你的建构要搭好。 它真的像是在作swing或者其他UI的桌面应用。
 我们用基于Controller和IView实现的GWT生成了全部的ui.除了gwt模块引入以外,那里没有html。
  这是对几乎所有主流web应用范例的违背,但是如果你喜欢ui编程,他完美的抽象了ajax/dhtml的行为到一个十分友好和可扩展的api.
  我或许会说如果你的工作是php,asp或者其他语言,你或许需要花更多的功夫。如果你已经是一个有经验的java程序员,那么你可以很快投入其中。

posted @ 2006-07-08 13:47 binge 阅读(1164) | 评论 (0)编辑 收藏

java.util.Date和java.sql.Date

java.sql.Date,java.sql.Time和java.sql.Timestamp三个都是java.util.Date的子类(包装类)。
但是为什么java.sql.Date类型的值插入到数据库中Date字段中会发生数据截取呢?
java.sql.Date是为了配合SQL DATE而设置的数据类型。“规范化”的java.sql.Date只包含年月日信息,时分秒毫秒都会清零。格式类似:YYYY-MM-DD
当我们调用ResultSet的getDate()方法来获得返回值时,java程序会参照"规范"的java.sql.Date来格式化数据库中的数值。因此,如果
数据库中存在的非规范化部分的信息将会被劫取。在sun提供的ResultSet.java中这样对getDate进行注释的:
Retrieves the value of the designated column in the current row of this <code>ResultSet</code> object as a “java.sql.Date” object in the Java programming language.
同理。如果我们把一个java.sql.Date值通过PrepareStatement的setDate方法存入数据库时,java程序会对传入的java.sql.Date规范化
,非规范化的部分将会被劫取。
 然而,我们java.sql.Date一般由java.util.Date转换过来,如:java.sql.Date sqlDate=new java.sql.Date(new java.util.Date().getTime()).
 显然,这样转换过来的java.sql.Date往往不是一个规范的java.sql.Date.
 在http://www.thunderguy.com/semicolon/2003/08/14/java-sql-date-is-not-a-real-date/ 文章中提到,要保存java.util.Date的精确值,
 我们需要利用java.sql.Timestamp.
 感谢这篇文章的铺垫:http://community.csdn.net/Expert/topic/4354/4354971.xml?temp=.5256616

posted @ 2006-07-06 16:51 binge 阅读(4276) | 评论 (0)编辑 收藏

log4j配置概要

官方网址:
http://logging.apache.org/log4j/docs/index.html

一个中文翻译的文档:

http://www.jaxwiki.org/zh/project/logging.apache.org/log4j/docs/manual.html


我摘出黄色字体表明几条列在下面,也是笔者认为log4j最主要特点的浓缩:

1.阶层式的命名:

      如果一个logger 的名字后面跟着一个点号(dot),它就是点号(dot)后面的那个logger的前辈( ancestor),是这个晚辈(descendant) 的前缀。如果在它自己和这个晚辈之间没有其它的前辈,它和这个晚辈之间就是关系。

2.级别继承

   对于一个给定的logger C,它继承的级别等于logger阶层里,从C开始往root logger上去的第一个non-null级别。


3.执行规则

   在一个级别为q(被指定的或继承的)的logger里,一个级别为p的日志请求,只有在p >= q 时才能够被执行。

4.appender添加性的规则

Logger C的log输出信息将被输出到C的所有appenders和它的前辈的 appenders。这就是"appender additivity"的意思。但是,如果logger C的前辈,比如说P,P的additivity flag被设置为 false,那么,C的输出信息将被输出到C的所有appenders中去,以及它的前辈的——截止在P那里,包括P在内的,appenders中去,但是不会输出到P的前辈的 appenders中去。 默认情况下,Loggers的additivity flag设置为true

关于日志格式:暂贴几个样例:
log4j.appender.A1.layout.ConversionPattern=%d %-5p [%t] %-c (%13F:%L) %3x - %m%n

在配置文件中,log4j可以访问到系统环境变量。具体的变量参考相关资料。
一篇我很早以前在csdn写的文章:
http://blog.csdn.net/huabingl/archive/2005/02/19/293933.aspx

posted @ 2006-07-04 10:07 binge 阅读(527) | 评论 (0)编辑 收藏

Mysql数据库使用技巧

  我承认我用mysql有很长时间了,不过似乎我仍然很白。好吧,还是写写吧。
  1。1067错误,无法启动。7/3/2006
     解决步骤和方案:察看日至,mysql.user表莫名其妙的弄丢了。从其他地方扒下一个放在这里就可以了。
 2.非安装版mysql的安装和启动。
     一般情况下,本人习惯用非安装版的软件。为了安装方便,你可以把解压后的文件拷贝到c盘根目录下,并把总目录改为mysql.然后进入windows命令 控制台,在c:/mysql/bin下面运行mysqld-nt --install把它安装为一个服务,然后调用net start mysql启动它,停止的命令是net stop mysql  .想要移除这个服务,用命令mysqld-nt --remove
 3.访问mysql的命令:mysql -h host -u user -p 。不过有好多好用的客户端可以使用,比如5.0自带的工具和SQLyog Enterprise
 4。库表相关的命令:SHOW DATABASES;SHOW TABLES;DESCRIBE table1/desc table1;
 5.察看当前配置:show variables;
 6.关于中文乱码问题,到一定积累,笔者准备开专题。目前简要列下:
   在mysql的一次会话中,服务器收到客户端发来的指令后,大致要执行3个动作:
  1、服务器认为收到的指令是按当前character_set_client环境变量所指定的字符集编码的,
  2、然后再将其转换成character_set_connection所指定的字符集编码
  3、分析、执行该指令。
  4、 用character_set_results变量所指定的字符集返回服务器向客户端传输的数据
 解决这个问题的关键点在于设置 default-character-set 变量。
7,在创建数据库的时候,我们有时会需要提供一些编码上的参数,如:
#1. Create mvnforum database with the "Create database" syntax (for unicode and others):
#   mysql> CREATE DATABASE mvnforum CHARACTER SET [charater_set] COLLATE [collation]
#  mysql> CREATE DATABASE mvnforum CHARACTER SET utf8 collate
#   Where charater_set and collation : @see http://dev.mysql.com/doc/refman/4.1/en/charset-mysql.html
#
#   a, practice to view all supported character set
#      mysql> SHOW CHARACTER SET;
#   b, practice to view all supported collation:
#      mysql> SHOW COLLATION;
#
#   c, Example for Unicode:
#      mysql> CREATE DATABASE mvnforum CHARACTER SET utf8 COLLATE utf8_general_ci
#"
"
   未完待续。
  欢迎回帖。

posted @ 2006-07-03 23:16 binge 阅读(1435) | 评论 (2)编辑 收藏

关于异常Exception

1。什么是异常
   异常是一种状态,是程序出现了符合该异常条件的一种状态。因此,他也可以说成是一种条件。
2。为什么要捕获异常
  捕获异常是为了对程序中出现的某种状况进行处理。如果有异常而没有捕获,异常将会向上一层传播,最终导致线程在此中止。
3。什么是check异常和unchecked异常
  uncheck异常一般是RuntimeException.出现这类异常,编译器不会强制要用户去捕获(当然你可以捕获)。   编译器会强制要求用户对checked异常进行捕获并作出一定的处理。
4。为什么不推荐捕获顶层异常(Exception)
  程序中会发生各种各样的异常。除非你的程序是个终端(一个业务的终点),否则不推荐捕获顶层异常。
 在程序的中间环节捕获所有异常毫无意义,并有可能导致流程上的隐患。比如,出现某种异常后,期望线程就此结束,不去做下面的工作,但是如果在中间环节对顶层异常进行了非法处理,程序有可能会运行下去,将导致不可控的错误。
5。为什么要自定义异常
 自定义异常是为了设置异常链的起点。一般情况下,我们都是允许每个程序员看到所有的异常信息,这个时候大多数都是把下一层的异常直接重掷到上一层。然而在多层次的结构中,我们有时候需要隐藏底层异常(这种异常的信息很多,很枯燥),而给消费者提供一个更为直观的异常,这个时候我们需要自定义异常。有的异常类jdk已经给我们提供,比如常用的IllegalArgumentException。如果你想在此再作包装,你可以创建自己的异常类。如此,消费者将以此异常作为异常链的起点。
6。为什么要重掷异常
 重掷异常是处理异常的一种方式。在捕获了某种异常后,用户可能不希望在这一层做出裁决,或者即使做出了一定的处理,但仍然需要向上一层报告,因此需要重掷异常。
7。异常机制。
   一旦某个点发生异常,这个点下面和catch语句之间的代码将不会被执行。因此,异常是一种中止流程的很有效的机制。
   关于异常,在effective java中提到“异常转译”和“异常连接”的概念。本人倾向于用“异常转译”,前提是要配置log4j,并作详细的日志纪录。

posted @ 2006-06-29 11:40 binge 阅读(1385) | 评论 (1)编辑 收藏

XMLBeans

 XmlBeans由 BEA公司发明,后捐赠给Apache基金会的。
 在项目中遇到这样的需求,根据已有的schema对xml进行格式校验,并读取出xml得数据。
 在大搜一番后,我最终把目光停留在xmlbeans上面。被淘汰的是digester.
 下面是一篇dev2dev得文章:
  http://dev2dev.bea.com/pub/a/2006/05/xmlbeans-2.html?page=4
 我就不炒饭了。
 好心的人给简单翻译了一下:
http://dev2dev.bea.com.cn/techdoc/200403127.html
 翻译得内容很少,有空本人补上。
ibm dw上也有个豆腐块:
http://www-128.ibm.com/developerworks/cn/xml/x-beans1/
关于digester的内容,只选了一篇文章:来自devx得
http://www.devx.com/Java/Article/21832/1763

关于2中方法的对比,他们的文章已经说的很详细了。

xmlbeans采用的是sax来读取数据。2004年,由bea公司发明的stax(stream API for XML)已经被jcp列为标准jsr-173,在jdk6.0中会出现。
 
关于stax,sax和dom的对比超出本篇范围,在此略过。
后记:
  在正在完成的项目中,我采用了xmlbeans,它的引入给我带来了很大的方便.

posted @ 2006-06-21 13:50 binge 阅读(621) | 评论 (0)编辑 收藏

仅列出标题
共4页: 上一页 1 2 3 4 下一页