posted @ 2006-11-23 23:47 killvin| 編輯 收藏
posted @ 2006-10-29 15:54 killvin| 編輯 收藏
We are dedicated to make Bindows work at least as well with Mozilla 1.4+ as it does with Internet Explorer 6.0 SP1. The Mozilla support is now integral part of Bindows and we will continue to develop, maintain and support it.
However, some issues are not solved yet and this document details them.
Known Issues
Web Services
We do not yet have a working SOAP web service client working with Mozilla. Mozilla has a built in web service client but it does not yet work with all the major web services platforms. We anticipate this to be resolve in a near future version of Bindows.
Graphs, Charts and Gauges
Graphs, charts and gauges are not supported. For the Bindows charts and gauges we rely on VML to do the drawing. Mozilla does not yet have a way to draw vector graphics at the client side without using a plugin. We consider several alternatives here but there is no time frame for a solution yet.
Miscellaneous
The caret is sometimes not shown in a focused textfield. This is a Mozilla bug and unless this is fixed in Mozilla this issue will remain.
Preferred size is not working consistently. Please report the cases where you are experiencing issues with the preferred size and we will see what can be done in those specific cases.
Icons in menu items works inconsistently between Mozilla versions. This is due to differences in the Mozilla toolkits used by different browsers.
Menu labels do not accept HTML. If you use HTML, the markup will be stripped.
The rendering of the group box is incorrect.
Labels with text align center and icon position set to top or bottom are a bit jumpy, ie. the icon move around depending on the state.
Dragging elements sometimes inconsistent. If an image is dragged an OS level drag and drop is initiated. Also, for some components a dragging will not work when the mouse leaves the browser window or enters a frame.
The upper border for the tab pages are not correctly drawn in Mozilla Firefox using Windows Classic. This is a Mozilla bug.
BiKeyboardEvent keyCode is sometimes incorrect in a keypress event (for special keys). The reason for this bug is that Internet Explorer and Mozilla are handling keyboard events differently.
Resize events are not fired on all BiComponents.
Focus and blur events are inconsistent when using BiRichEdit.
posted @ 2006-10-14 16:21 killvin| 編輯 收藏
Jsparse is a parse?to parse the schema file?with javascript.
If you are interested in it, you can vist the url
http://code.google.com/p/jsparse/
?
svn checkout http://jsparse.googlecode.com/svn/trunk/ jsparse
posted @ 2006-09-13 23:23 killvin| 編輯 收藏
ACE中的Double Checked Locking 模式
(作者:Douglas C. Schmidt ,by huihoo.org CORBA課題 Thzhang 譯 , Allen整理,制作)
意圖
無(wú)論什么時(shí)候當(dāng)臨界區(qū)中的代碼僅僅需要加鎖一次,同時(shí)當(dāng)其獲取鎖的時(shí)候必須是線程安全的,可以用Double Checked Locking 模式來(lái)減少競(jìng)爭(zhēng)和加鎖載荷。動(dòng)機(jī)
1、標(biāo)準(zhǔn)的單例。開(kāi)發(fā)正確的有效的并發(fā)應(yīng)用是困難的。程序員必須學(xué)習(xí)新的技術(shù)(并發(fā)控制和防止死鎖的算法)和機(jī)制(如多線程和同步API)。此外,許多熟悉的設(shè)計(jì)模式(如單例和迭代子)在包含不使用任何并發(fā)上下文假設(shè)的順序程序中可以工作的很好。為了說(shuō)明這點(diǎn),考慮一個(gè)標(biāo)準(zhǔn)的單例模式在多線程環(huán)境下的實(shí)現(xiàn)。單例模式保證一個(gè)類僅有一個(gè)實(shí)例同時(shí)提供了全局唯一的訪問(wèn)這個(gè)實(shí)例的入口點(diǎn)。在c++程序中動(dòng)態(tài)分配單例對(duì)象是通用的方式,這是因?yàn)閏++程序沒(méi)有很好的定義靜態(tài)全局對(duì)象的初始化次序,因此是不可移植的。而且,動(dòng)態(tài)分配避免了單例對(duì)象在永遠(yuǎn)沒(méi)有被使用情況下的初始化開(kāi)銷(xiāo)。
class Singleton
{
public:
static Singleton *instance (void)
{
if (instance_ == 0)
// Critical section.
instance_ = new Singleton;
return instance_;
}
void method (void);
// Other methods and members omitted.
private:
static Singleton *instance_;
};
應(yīng)用代碼在使用單例對(duì)象提供的操作前,通過(guò)調(diào)用靜態(tài)的instance方法來(lái)獲取單例對(duì)象的引用,如下所示:
Singleton::instance ()->method ();
2、問(wèn)題:競(jìng)爭(zhēng)條件。不幸的是,上面展示的標(biāo)準(zhǔn)單例模式的實(shí)現(xiàn)在搶先多任務(wù)和真正并行環(huán)境下無(wú)法正常工作。例如,如果在并行主機(jī)上運(yùn)行的多個(gè)線程在單例對(duì)象初始化之前同時(shí)調(diào)用Singleton::instance方法,Singleton的構(gòu)造函數(shù)將被調(diào)用多次,這是因?yàn)槎鄠€(gè)線程將在上面展示的臨界區(qū)中執(zhí)行new singleton操作。臨界區(qū)是一個(gè)必須遵守下列定式的指令序列:當(dāng)一個(gè)線程/進(jìn)程在臨界區(qū)中運(yùn)行時(shí),沒(méi)有其他任何線程/進(jìn)程會(huì)同時(shí)在臨界區(qū)中運(yùn)行。在這個(gè)例子中,單例的初始化過(guò)程是一個(gè)臨界區(qū),違反臨界區(qū)的原則,在最好的情況下將導(dǎo)致內(nèi)存泄漏,最壞的情況下,如果初始化過(guò)程不是冪等的(idempotent.),將導(dǎo)致嚴(yán)重的后果。
3、 通常的陷阱和弊端。實(shí)現(xiàn)臨界區(qū)的通常方法是在類中增加一個(gè)靜態(tài)的Mutex對(duì)象。這個(gè)Mutex保證單例的分配和初始化是原子操作,如下:
class Singleton
{
public:
static Singleton *instance (void)
{
// Constructor of guard acquires lock_ automatically.
Guard guard (lock_);
// Only one thread in the critical section at a time.
if (instance_ == 0)
instance_ = new Singleton;
return instance_;
// Destructor of guard releases lock_ automatically.
}
private:
static Mutex lock_;
static Singleton *instance_;
};
guard類使用了一個(gè)c++的習(xí)慣用法,當(dāng)這個(gè)類的對(duì)象實(shí)例被創(chuàng)建時(shí),它使用構(gòu)造函數(shù)來(lái)自動(dòng)獲取一個(gè)資源,當(dāng)類對(duì)象離開(kāi)一個(gè)區(qū)域時(shí),使用析構(gòu)器來(lái)自動(dòng)釋放這個(gè)資源。通過(guò)使用guard,每一個(gè)對(duì)Singleton::instance方法的訪問(wèn)將自動(dòng)的獲取和釋放lock_。
即使這個(gè)臨界區(qū)只是被使用了一次,但是每個(gè)對(duì)instance方法的調(diào)用都必須獲取和釋放lock_。雖然現(xiàn)在這個(gè)實(shí)現(xiàn)是線程安全的,但過(guò)多的加鎖負(fù)載是不能被接受的。一個(gè)明顯(雖然不正確)的優(yōu)化方法是將guard放在針對(duì)instance進(jìn)行條件檢測(cè)的內(nèi)部:
static Singleton *instance (void)
{
if (instance_ == 0) {
Guard guard (lock_);
// Only come here if instance_ hasn't been initialized yet.
instance_ = new Singleton;
}
return instance_;
}
這將減少加鎖負(fù)載,但是不能提供線程安全的初始化。在多線程的應(yīng)用中,仍然存在競(jìng)爭(zhēng)條件,將導(dǎo)致多次初始化instance_。例如,考慮兩個(gè)線程同時(shí)檢測(cè) instance_ == 0,都將會(huì)成功,一個(gè)將通過(guò)guard獲取lock_另一個(gè)將被阻塞。當(dāng)?shù)谝痪€程初始化Singleton后釋放lock_,被阻塞的線程將獲取lock_,錯(cuò)誤的再次初始化Singleton。 4、解決之道,Double Checked Locking優(yōu)化。解決這個(gè)問(wèn)題更好的方法是使用Double Checked Locking。它是一種用于清除不必要加鎖過(guò)程的優(yōu)化模式。具有諷刺意味的是,它的實(shí)現(xiàn)幾乎和前面的方法一樣。通過(guò)在另一個(gè)條件檢測(cè)中包裝對(duì)new的調(diào)用來(lái)避免不必要的加鎖:
class Singleton
{
public:
static Singleton *instance (void)
{
// First check
if (instance_ == 0)
{
// Ensure serialization (guard constructor acquires lock_).
Guard guard (lock_);
// Double check.
if (instance_ == 0)
instance_ = new Singleton;
}
return instance_;
// guard destructor releases lock_.
}
private:
static Mutex lock_;
static Singleton *instance_;
};
第一個(gè)獲取lock_的線程將構(gòu)建Singleton,并將指針?lè)峙浣oinstance_,后續(xù)調(diào)用instance方法的線程將發(fā)現(xiàn)instance_ != 0,于是將跳過(guò)初始化過(guò)程。如果多個(gè)線程試圖并發(fā)初始化Singleton,第二個(gè)檢測(cè)件阻止競(jìng)爭(zhēng)條件的發(fā)生。在上面的代碼中,這些線程將在lock_上排隊(duì),當(dāng)排隊(duì)的線程最終獲取lock_時(shí),他們將發(fā)現(xiàn)instance_ != 0于是將跳過(guò)初始化過(guò)程。
上面Singleton::instance的實(shí)現(xiàn)僅僅在Singleton首次被初始化時(shí),如果有多個(gè)線程同時(shí)進(jìn)入instance方法將導(dǎo)致加鎖負(fù)載。在后續(xù)對(duì)Singleton::instance的調(diào)用因?yàn)閕nstance_ != 0而不會(huì)有加鎖和解鎖的負(fù)載。 通過(guò)增加一個(gè)mutex和一個(gè)二次條件檢測(cè),標(biāo)準(zhǔn)的單例實(shí)現(xiàn)可以是線程安全的,同時(shí)不會(huì)產(chǎn)生過(guò)多的初始化加鎖負(fù)載。
適應(yīng)性
> 當(dāng)一個(gè)應(yīng)用具有下列特征時(shí),可以使用Double Checked Locking優(yōu)化模式:1、應(yīng)用包含一個(gè)或多個(gè)需要順序執(zhí)行的臨界區(qū)代碼。
2、多個(gè)線程可能潛在的試圖并發(fā)執(zhí)行臨界區(qū)。
3、臨界區(qū)僅僅需要被執(zhí)行一次。
4、在每一個(gè)對(duì)臨界區(qū)的訪問(wèn)進(jìn)行加鎖操作將導(dǎo)致過(guò)多加鎖負(fù)載。
5、在一個(gè)鎖的范圍內(nèi)增加一個(gè)輕量的,可靠的條件檢測(cè)是可行的。
結(jié)構(gòu)和參與者
通過(guò)使用偽代碼能夠最好地展示Double Checked Locking模式的結(jié)構(gòu)和參與者,圖1展示了在Double Checked Locking模式有下列參與者:1、僅有一次臨界區(qū)(Just Once Critical Section,)。臨界區(qū)所包含的代碼僅僅被執(zhí)行一次。例如,單例對(duì)象僅僅被初始化一次。這樣,執(zhí)行對(duì)new Singleton的調(diào)用(只有一次)相對(duì)于Singleton::instance方法的訪問(wèn)將非常稀少。
2、mutex。鎖被用來(lái)序列化對(duì)臨界區(qū)中代碼的訪問(wèn)。
3、標(biāo)記。標(biāo)記被用來(lái)指示臨界區(qū)的代碼是否已經(jīng)被執(zhí)行過(guò)。在上面的例子中單例指針instance_被用來(lái)作為標(biāo)記。
4、 應(yīng)用線程。試圖執(zhí)行臨界區(qū)代碼的線程。
協(xié)作
圖2展示了Double Checked Locking模式的參與者之間的互動(dòng)。作為一種普通的優(yōu)化用例,應(yīng)用線程首先檢測(cè)flag是否已經(jīng)被設(shè)置。如果沒(méi)有被設(shè)置,mutex將被獲取。在持有這個(gè)鎖之后,應(yīng)用線程將再次檢測(cè)flag是否被設(shè)置,實(shí)現(xiàn)Just Once Critical Section,設(shè)定flag為真。最后應(yīng)用線程釋放鎖。結(jié)論
使用Double Checked Locking模式帶來(lái)的幾點(diǎn)好處:1、最小化加鎖。通過(guò)實(shí)現(xiàn)兩個(gè)flag檢測(cè),Double Checked Locking模式實(shí)現(xiàn)通常用例的優(yōu)化。一旦flag被設(shè)置,第一個(gè)檢測(cè)將保證后續(xù)的訪問(wèn)不要加鎖操作。
2、防止競(jìng)爭(zhēng)條件。對(duì)flag的第二個(gè)檢測(cè)將保證臨界區(qū)中的事件僅實(shí)現(xiàn)一次。
使用Double Checked Locking模式也將帶來(lái)一個(gè)缺點(diǎn):產(chǎn)生微妙的移植bug的潛能。這個(gè)微妙的移植問(wèn)題能夠?qū)е轮旅腷ug,如果使用Double Checked Locking模式的軟件被移植到?jīng)]有原子性的指針和正數(shù)賦值語(yǔ)義的硬件平臺(tái)上。例如,如果一個(gè)instance_指針被用來(lái)作為Singleton實(shí)現(xiàn)的flag,instance_指針中的所有位(bit)必須在一次操作中完成讀和寫(xiě)。如果將new的結(jié)果寫(xiě)入內(nèi)存不是一個(gè)原子操作,其他的線程可能會(huì)試圖讀取一個(gè)不健全的指針,這將導(dǎo)致非法的內(nèi)存訪問(wèn)。
在一些允許內(nèi)存地址跨越對(duì)齊邊界的系統(tǒng)上這種現(xiàn)象是可能的,因此每次訪問(wèn)需要從內(nèi)存中取兩次。在這種情況下,系統(tǒng)可能使用分離的字對(duì)齊合成flag,來(lái)表示instance_指針。
如果一個(gè)過(guò)于激進(jìn)(aggressive)編譯器通過(guò)某種緩沖手段來(lái)優(yōu)化flag,或是移除了第二個(gè)flag==0檢測(cè),將帶來(lái)另外的相關(guān)問(wèn)題。后面會(huì)介紹如何使用volatile關(guān)鍵字來(lái)解決這個(gè)問(wèn)題。
實(shí)現(xiàn)和例子代碼
ACE在多個(gè)庫(kù)組件中使用Double Checked Locking模式。例如,為了減少代碼的重復(fù),ACE使用了一個(gè)可重用的適配器ACE Singleton來(lái)將普通的類轉(zhuǎn)換成具有單例行為的類。下面的代碼展示了如何用Double Checked Locking模式來(lái)實(shí)現(xiàn)ACE Singleton。
// A Singleton Adapter: uses the Adapter
// pattern to turn ordinary classes into
// Singletons optimized with the
// Double-Checked Locking pattern.
template
class ACE_Singleton
{
public:
static TYPE *instance (void);
protected:
static TYPE *instance_;
static LOCK lock_;
};
template TYPE *
ACE_Singleton::instance ()
{
// Perform the Double-Checked Locking to
// ensure proper initialization.
if (instance_ == 0) {
ACE_Guard lock (lock_);
if (instance_ == 0)
instance_ = new TYPE;
}
return instance_;
}
ACE Singleton類被TYPE和LOCK來(lái)參數(shù)化。因此一個(gè)給定TYEP的類將被轉(zhuǎn)換成使用LOCK類型的互斥量的具有單例行為的類。
ACE中的Token Manager.是使用ACE Singleton的一個(gè)例子。Token Manager實(shí)現(xiàn)在多線程應(yīng)用中對(duì)本地和遠(yuǎn)端的token(一種遞歸鎖)死鎖檢測(cè)。為了減少資源的使用,Token Manager被按需創(chuàng)建。為了創(chuàng)建一個(gè)單例的Token Manager對(duì)象,只是需要實(shí)現(xiàn)下面的typedef:
typedef ACE_Singleton
Token Manager單例將被用于本地和遠(yuǎn)端的token死鎖檢測(cè)。在一個(gè)線程阻塞等待互斥量之前,它首先查詢Token Manager單例,來(lái)測(cè)試阻塞是否會(huì)導(dǎo)致死鎖狀態(tài)。對(duì)于系統(tǒng)中的每一個(gè)token,Token Manager單例維護(hù)一個(gè)持有token線程和所有阻塞等待在該token的線程記錄鏈表。這些數(shù)據(jù)將提供充足的檢測(cè)死鎖狀態(tài)的依據(jù)。使用Token Manager單例的過(guò)程如下:
// Acquire the mutex.
int Mutex_Token::acquire (void)
{
// If the token is already held, we must block.
if (mutex_in_use ()) {
// Use the Token_Mgr Singleton to check
// for a deadlock situation *before* blocking.
if (Token_Mgr::instance ()->testdeadlock ()) {
errno = EDEADLK;
return -1;
}
else
// Sleep waiting for the lock...
// Acquire lock...
}
變化
一種變化的Double Checked Locking模式實(shí)現(xiàn)可能是需要的,如果一個(gè)編譯器通過(guò)某種緩沖方式優(yōu)化了flag。在這種情況下,緩沖的粘著性(coherency)將變成問(wèn)題,如果拷貝flag到多個(gè)線程的寄存器中,會(huì)產(chǎn)生不一致現(xiàn)象。如果一個(gè)線程更改flag的值將不能反映在其他線程的對(duì)應(yīng)拷貝中。另一個(gè)相關(guān)的問(wèn)題是編譯器移除了第二個(gè)flag==0檢測(cè),因?yàn)樗鼘?duì)于持有高度優(yōu)化特性的編譯器來(lái)說(shuō)是多余的。例如,下面的代碼在激進(jìn)的編譯器下將被跳過(guò)對(duì)flag的讀取,而是假定instance_還是為0,因?yàn)樗鼪](méi)有被聲明為volatile的。
Singleton *Singleton::instance (void)
{
if (Singleton::instance_ == 0)
{
// Only lock if instance_ isn't 0.
Guard guard (lock_);
// Dead code elimination may remove the next line.
// Perform the Double-Check.
if (Singleton::instance_ == 0)
// ...
解決這兩個(gè)問(wèn)題的一個(gè)方法是生命flag為Singleton的volatile成員變量,如下:
private:
static volatile long Flag_; // Flag is volatile.
使用volatile將保證編譯器不會(huì)將flag緩沖到編譯器,同時(shí)也不會(huì)優(yōu)化掉第二次讀操作。使用volatile關(guān)鍵字的言下之意是所有對(duì)flag的訪問(wèn)是通過(guò)內(nèi)存,而不是通過(guò)寄存器。
相關(guān)模式
Double Checked Locking模式是First-Time-In習(xí)慣用法的一個(gè)變化。First-Time-In習(xí)慣用法經(jīng)常使用在類似c這種缺少構(gòu)造器的程序語(yǔ)言中,下面的代碼展示了這個(gè)模式:
static const int STACK_SIZE = 1000;
static T *stack_;
static int top_;
void push (T *item)
{
// First-time-in flag
if (stack_ == 0) {
stack_ = malloc (STACK_SIZE * sizeof *stack);
assert (stack_ != 0);
top_ = 0;
}
stack_[top_++] = item;
// ...
}
第一次push被調(diào)用時(shí),stack_是0,這將導(dǎo)致觸發(fā)malloc來(lái)初始化它自己。
posted @ 2006-09-13 23:16 killvin| 編輯 收藏
IE
GET /mail HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon)
Host: mail.google.com
Connection: Keep-Alive
Cookie: gmailchat=killvin.liu@gmail.com/519974 ; PREF=ID=d68c481e542af276:NW=1:TM=1151742225:LM=1151742225:S=2qbdhg0_z3i-OAbW; SID=DQAAAG8AAACEdcjD2IZMNqZVatDbD62X8_U18oJuTVQc9XZUJi7MgCkM8sggJ8M5npZ35GXjdalT2o8QWPUve04tepy61MPv4v_EpILafg3JdIf8AFjD91aMT0tI5gb763FouV3e_2-C364HDO5Qzb4P4gjjgpHC
Firefox
GET /mail HTTP/1.1
Host: mail.google.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
我們可以注意到:如果用戶關(guān)閉了瀏覽器的Cookie選項(xiàng),在Firefox中對(duì)于新的請(qǐng)求是包含Cookie的信息的,然而IE卻恰恰相反!這也就直接用IE瀏覽一些網(wǎng)站所導(dǎo)致的Cookie校驗(yàn)失敗問(wèn)題(比如即使用戶在使用過(guò)程中突然關(guān)閉Cookie,依然可以自由的訪問(wèn)網(wǎng)站的各項(xiàng)服務(wù)),進(jìn)一步,如果某個(gè)網(wǎng)站是讀取依靠Cookie中的信息來(lái)驗(yàn)證用戶(尤其是那種保存客戶信息的提示),即使這個(gè)用戶離開(kāi)或者關(guān)閉窗口,任何一個(gè)后來(lái)的人都可以輕松的瀏覽這個(gè)用戶的私有信息!這就是Cookie的最大的問(wèn)題所在,當(dāng)然這是另外的話題,不屬于本次討論的范疇,這一次要說(shuō)的是 如何避免IE瀏覽器下,用戶關(guān)閉Cookie的問(wèn)題。
有一個(gè)思路,經(jīng)過(guò)測(cè)試我們發(fā)現(xiàn)IE瀏覽器只是在首次頁(yè)面請(qǐng)求的時(shí)候才會(huì)去讀取Cookie的值,所以,為了避免IE瀏覽器關(guān)閉Cookie的問(wèn)題,可以在用戶請(qǐng)求某個(gè)鏈接的時(shí)候,先將用戶的Cookie存放在某處,并清空此時(shí)所有的Cookie值,再次的請(qǐng)求頁(yè)面,而這樣做的目的就是強(qiáng)迫IE讀取硬盤(pán)上的Cookie,如果此時(shí)用戶關(guān)閉了Cookie,就不會(huì)在請(qǐng)求的頭信息中看到Cookie信息;如果沒(méi)有關(guān)閉Cookie,就可以放心的將原先的Cookie寫(xiě)回Reponse對(duì)象。
只是不知道Google的網(wǎng)站是否也是按照這個(gè)思路去解決此問(wèn)題的?
posted @ 2006-07-02 21:53 killvin| 編輯 收藏
IE在處理COOKIE方面的問(wèn)題
1。即使你提高了瀏覽器的隱私登記,在第一次打開(kāi)窗口的時(shí)候,你獲取不到任何的Cookies對(duì)象(很顯然的結(jié)果),然而當(dāng)你再次刷新本頁(yè)面的,Cookie此時(shí)會(huì)奇跡般的出現(xiàn)!而在Firefox瀏覽器中按照以上的步驟,是不會(huì)出現(xiàn)這樣的情況的。
2。不僅如此,你還可以透過(guò)Action的處理,多次的往Cookie中增加Cookie的數(shù)量(當(dāng)然在Action中你依然可以自由的獲取到Cookie這個(gè)數(shù)組,并且不為空),然而讓人匪夷所思的是在Cookie的存放目錄下你是找尋不到任何的蛛絲馬跡的。而在Firefox沒(méi)有出現(xiàn)以上的情況。
-解決
1。在首次進(jìn)入頁(yè)面時(shí)查詢客戶端的Cookie,如果不存在則警告用戶,并要求再次的登陸。
2。在用戶登陸后,如果更改了瀏覽器的隱私級(jí)別,對(duì)于Firefox標(biāo)準(zhǔn)的瀏覽器,此時(shí)肯定不會(huì)再找到Cookie數(shù)組對(duì)象了,你需要做的僅僅只是將頁(yè)面調(diào)轉(zhuǎn)到登陸窗口;而在IE下就非常的麻煩了甚至無(wú)法解決,因?yàn)槟阋廊豢梢栽L問(wèn)到原來(lái)的Cookie數(shù)組值,(比如,用IE在CSDN登陸后提高隱私級(jí)別,你依然可以登陸到其他的服務(wù)區(qū)域)此時(shí)沒(méi)有什么好的辦法,不過(guò)Google解決了這樣的問(wèn)題,只是不知道如何解決的。
IE在處理Frame標(biāo)記的問(wèn)題
1。如果你在某個(gè)頁(yè)面中嵌入了Frame標(biāo)簽,并且希望與這個(gè)嵌入的頁(yè)面共享某些存放在Session中的數(shù)據(jù),此時(shí)你需要將外部的sessionId傳入到frame標(biāo)記的頁(yè)面中。然而在IE中你可能并不能完全的享受這樣的邏輯,原因在于IE對(duì)于嵌入的頁(yè)面不會(huì)自動(dòng)的傳遞sessionId,也許你碰巧可以,也許不行,也就是說(shuō)完全是在IE的"掌控"之下。而在Firefox沒(méi)有出現(xiàn)這樣的情況。
-解決
為嵌入的頁(yè)面中所有的鏈接增加sessionId參數(shù)。
最好的辦法就是:說(shuō)服客戶使用標(biāo)準(zhǔn)的瀏覽器Firefox!
posted @ 2006-07-01 15:53 killvin| 編輯 收藏
在Struts中我們經(jīng)常這樣循環(huán)的打印Message
<logic:messagesPresent message="true">
? <html:messages id="msg" message="true">
??? <div class="success">
????? <bean:write name="msg"/>
??? </div><br/>
? </html:messages>
</logic:messagesPresent>
查閱struts tag的文檔我們看到了關(guān)于messagesPresent的message屬性注釋如下
message |
By default the tag will retrieve the request scope bean it will iterate over from the |
也就是說(shuō)在將message設(shè)置為true時(shí),會(huì)去request中尋找Globals.MESSAGE_KEY所代表的bean,然而我們?cè)诰唧w的Action使用ActionMessages類的時(shí)候往往是這樣的
ActionMessages messages = getErrors(request);
messages.add(ActionMessages.GLOBAL_MESSAGE , new ActionMessage(key , value0));
saveMessages(request,messages);
而往往困擾人的就在于為什么要給messages中放入名稱為"ActionMessages.GLOBAL_MESSAGE"的ActionMessage對(duì)象,而且還需要再次的調(diào)用saveErrors(request,messages)方法?
首先要說(shuō)明的是你為ActionMessage起任何的名稱都沒(méi)有關(guān)系,因?yàn)锳ctionMessages本身維持著一個(gè)HashMap,而參數(shù)property就是這個(gè)HashMap中的key值,如果不存在則會(huì)建立相應(yīng)的key,并將需要保存的ActionMessage對(duì)象存入到這個(gè)key所對(duì)應(yīng)的List中。
??? public void add(String property, ActionMessage message) {
??????? ActionMessageItem item = (ActionMessageItem) messages.get(property);
??????? List list = null;
??????? if (item == null) {
??????????? list = new ArrayList();
??????????? item = new ActionMessageItem(list, iCount++, property);
??????????? messages.put(property, item);
??????? } else {
??????????? list = item.getList();
??????? }
??????? list.add(message);
??? }
至于為什么一定要調(diào)用saveMessages(request,messages)?看看它具體的實(shí)現(xiàn)邏輯就清楚了
??? protected void saveMessages(
??????? HttpServletRequest request,
??????? ActionMessages messages) {
??????? // Remove any messages attribute if none are required
??????? if ((messages == null) || messages.isEmpty()) {
??????????? request.removeAttribute(Globals.MESSAGE_KEY);
??????????? return;
??????? }
??????? // Save the messages we need
??????? request.setAttribute(Globals.MESSAGE_KEY, messages);
??? }
再對(duì)比前面介紹的messagesPresent標(biāo)簽的使用,是不是就清楚了呢?原來(lái)它是將ActionMessages對(duì)象保存在request中,并且名稱是Globals.ERROR_KEY!從而為tag的順利解析鋪平了道路。當(dāng)然按理你可以選擇將這樣的對(duì)象放置在任何的scope中,但Action只是提供了request , session兩種Scope(不過(guò)page , application不經(jīng)常使用,可以理解,但不提供相應(yīng)的結(jié)構(gòu)就不太好了)
至于messagesPresent標(biāo)簽是如何在scope中尋找ActionMessages對(duì)象
org.apache.struts.taglib.logic.MessagesPresentTag
??? protected boolean condition(boolean desired) throws JspException {
??????? ActionMessages am = null;
??????? String key = name;
??????? if (message != null && "true".equalsIgnoreCase(message)){
?????????? key = Globals.MESSAGE_KEY;
??????? }
??????? try {
??????????? am = TagUtils.getInstance().getActionMessages(pageContext, key);
???????????
??????? } catch (JspException e) {
??????????? TagUtils.getInstance().saveException(pageContext, e);
??????????? throw e;
??????? }
??????? Iterator iterator = (property == null) ? am.get() : am.get(property);
??????? return (iterator.hasNext() == desired);
??? }
org.apache.struts.taglib.TagUtils
?? public ActionErrors getActionErrors(PageContext pageContext, String paramName)
??????????? throws JspException {
??????? ActionErrors errors = new ActionErrors();
??????? Object value = pageContext.findAttribute(paramName);
??????? if (value != null) {
??????????? try {
??????????????? if (value instanceof String) {
??????????????????? errors.add(
??????????????????????????? ActionMessages.GLOBAL_MESSAGE,
??????????????????????????? new ActionMessage((String) value));
??????????????? } else if (value instanceof String[]) {
??????????????????? String keys[] = (String[]) value;
??????????????????? for (int i = 0; i < keys.length; i++) {
??????????????????????? errors.add(
??????????????????????????????? ActionMessages.GLOBAL_MESSAGE,
??????????????????????????????? new ActionMessage(keys[i]));
??????????????????? }
??????????????? } else if (value instanceof ActionErrors) {
??????????????????? errors = (ActionErrors) value;
??????????????? } else {
??????????????????? throw new JspException(
??????????????????????????? messages.getMessage(
??????????????????????????????????? "actionErrors.errors",
??????????????????????????????????? value.getClass().getName()));
??????????????? }
??????????? } catch (JspException e) {
??????????????? throw e;
??????????? } catch (Exception e) {
??????????????? log.debug(e, e);
??????????? }
??????? }
??????? return errors;
??? }
PageContext中的findAttribute會(huì)幫你在scope中尋找名稱為Globals.MESSAGE_KEY的ActionMessage對(duì)象。
注意
雖然Struts已經(jīng)聲明:不推薦使用ActionErrors & ActionError對(duì)象,但在一些遺留的系統(tǒng)中,依然還是可以看到其影子,所以如果你的系統(tǒng)不幸屬于這樣的兩種混合系統(tǒng),有以下的幾種方法可以參考
1。兩次調(diào)用messagesPresent,如下
<!-- Print ActionErrors Object -->
<logic:messagesPresent>
? <html:messages id="msg" message="true">
??? <div class="success">
????? <bean:write name="msg"/>
??? </div><br/>
? </html:messages>
</logic:messagesPresent>
<!-- Print ActionMessages Object -->
<logic:messagesPresent message="true">
? <html:messages id="msg" message="true">
??? <div class="success">
????? <bean:write name="msg"/>
??? </div><br/>
? </html:messages>
</logic:messagesPresent>
2.分別使用<html:messages> <html:errors>標(biāo)簽,當(dāng)然在老系統(tǒng)中需要調(diào)用Action的saveErrors方法,而在新的應(yīng)用中要調(diào)用saveMessages方法。
3.更換所有的ActionErrors為ActionMessages,并將所有調(diào)用saveErrors的地方更換成saveMessages,并將<html:errors>標(biāo)簽相應(yīng)的更換成<html:messages message="true"> - 推薦!
?
posted @ 2006-06-27 23:02 killvin| 編輯 收藏
第2章 并發(fā)問(wèn)題及控制手段
什么是并發(fā)問(wèn)題?假設(shè)有這么一家書(shū)吧,顧客可以到那里喝茶讀書(shū)。顧客拿著選好要讀的圖書(shū)到柜臺(tái)登記,然后找個(gè)地方去閱讀,臨走時(shí)將圖書(shū)歸還店家。有一天,一個(gè)顧客相中了一本書(shū)后正要拿去登記,另一個(gè)顧客的手也抓住了這僅有的一本書(shū),并發(fā)問(wèn)題出現(xiàn)了。兩個(gè)顧客要讀同一本書(shū),互不相讓,這讓店主傷透了腦筋。這個(gè)案例僅僅是眾多并發(fā)問(wèn)題中的一個(gè)微小部分,但從中我們可以看出并發(fā)問(wèn)題主要出現(xiàn)在多個(gè)用戶對(duì)有限資源進(jìn)行訪問(wèn)的時(shí)候,如果解決不好會(huì)直接影響系統(tǒng)的有效、正常運(yùn)行。數(shù)據(jù)庫(kù)是一個(gè)共享的資源,并發(fā)問(wèn)題的出現(xiàn)是必不可免的,如何識(shí)別并發(fā)類型并加以控制是這一章重點(diǎn)要講述的內(nèi)容。
本章將分成兩大部分,一部分主要講Visual FoxPro中并發(fā)控制機(jī)制。VFP中并發(fā)控制相對(duì)簡(jiǎn)單,數(shù)據(jù)加鎖的形式比較單一,非常適合作為初步了解并發(fā)問(wèn)題的切入點(diǎn)。第二部分以SQL Server 2000、ADO.NET以及C#為主要工具,深入了解并發(fā)一致性問(wèn)題、封鎖協(xié)議、事務(wù)隔離等內(nèi)容,難度相對(duì)較深。象一些更為深入的并發(fā)控制手段,例如多粒度封鎖和意象鎖等內(nèi)容在本章中將不做深入討論,感興趣可以參考相關(guān)書(shū)籍。
?
[實(shí)在不好意思COPY別人的成果,不過(guò)這篇文章出奇的精彩,將并發(fā)操作的來(lái)龍去脈說(shuō)的清清楚楚,也是我正要找的,比JAVAEYE上面所謂的專家叫嚷著什么"悲觀鎖"、"樂(lè)觀鎖"而不解是原因要強(qiáng)的多!值得收藏]
posted @ 2006-04-06 10:57 killvin| 編輯 收藏
痛快!。。。人們總是認(rèn)為罵人是沒(méi)有素質(zhì)的象征,然而我到覺(jué)得要看對(duì)誰(shuí)而言,如果你的面前是個(gè)謙虛、嚴(yán)謹(jǐn)而又懂得尊重別人的人,你根本就不可能讓自己憤怒,也不可能讓自己表現(xiàn)的很沒(méi)有素質(zhì);相反如果你的面前是個(gè)先入為主、自傲、不懂得尊重別人的人,你的憤怒就會(huì)在最短的時(shí)間內(nèi)激發(fā)出來(lái)。-對(duì)于小人,就要罵!
而這有與北大青鳥(niǎo)有什么關(guān)系呢?
在我的職業(yè)生涯里,有一段讓自己憤怒的培訓(xùn)經(jīng)歷,到今天我都為自己在這樣的培訓(xùn)部的學(xué)習(xí)經(jīng)歷而感到恥辱!甚至不愿意在簡(jiǎn)歷里提及ACCP的字樣,而這樣的培訓(xùn)經(jīng)歷就是在北大青鳥(niǎo)(西安兆?。├锒冗^(guò)的。
我參加的是北大青鳥(niǎo)(西安兆隆)的第二期培訓(xùn),培訓(xùn)的課程涉及到數(shù)據(jù)庫(kù)、編程語(yǔ)言、職業(yè)素質(zhì)、項(xiàng)目實(shí)踐等,看上去非常的正規(guī),可是真正的學(xué)習(xí)效果卻是讓人非常的失望的!
首先,就是它的課程體系,完全的引入印度的教程,而翻譯的質(zhì)量非常的差,其實(shí)這到?jīng)]有什么,只是教程的講解范圍和深度都非常的淺(這還是第二期的培訓(xùn)),如果你只是按照它的教程我可以說(shuō)你根本學(xué)不到任何有價(jià)值的東西,只是皮毛而已。-拿著淡薄的教學(xué)資料的同時(shí)你也就上了賊船了。
再次,就是它的老師的水平實(shí)在不敢恭維,(當(dāng)然并不是說(shuō)根本就沒(méi)有好的老師,曾經(jīng)就遇到過(guò)一個(gè)講解JAVA與UML的老師,水平非常的高深,可惜ACCP沒(méi)有留住),比如編程語(yǔ)言中學(xué)習(xí)了VB,僅僅只是這一門(mén)課程就換了3個(gè)老師,最后是一位號(hào)稱是西工大的博士上的課,然而這位博士顯然是心思不再這里,除了講解課本上已經(jīng)有的代碼,根本不敢深入的講解原理,這門(mén)課程也就這樣混過(guò)去了。-如果這樣學(xué)習(xí)編程語(yǔ)言道不如自學(xué)來(lái)得輕松。
還有,就是所謂的項(xiàng)目實(shí)踐根本就不是老師帶的項(xiàng)目,而是一些書(shū)本上或者捏造出來(lái)的一些項(xiàng)目,比如圖書(shū)管理系統(tǒng)等,如果學(xué)員無(wú)法真正的理解需求,怎么去理解設(shè)計(jì),又如何來(lái)進(jìn)行實(shí)際的編碼呢?如果遇到圖書(shū)管理的專業(yè)問(wèn)題來(lái)問(wèn)誰(shuí)呢?-別指望在他們宣傳的所謂的項(xiàng)目實(shí)踐中得到鍛煉。
在看看他們引以為傲的工作分配問(wèn)題吧?就我個(gè)人的親身感受來(lái)言,這里會(huì)提供一些工作的機(jī)會(huì),但都是一些小公司,而且往往是一些前三個(gè)月不給工資的公司;當(dāng)時(shí)我在我們班級(jí)里是比較認(rèn)真的一個(gè)(我是班里唯一的一個(gè)交了對(duì)項(xiàng)目分析文檔的學(xué)員,并且是項(xiàng)目實(shí)踐中的小組組長(zhǎng)),可是在一次很好的面試機(jī)會(huì)面前,她們竟然由于工作的失誤忘記了給我打電話?!-如果這樣的工作分配策略也算作是給予你的答案的話,你一定會(huì)變得和我一樣的憤怒!
我沒(méi)有在ACCP學(xué)到任何的有用的東西,然而在真實(shí)的世界里卻學(xué)到了人們對(duì)于ACCP的看法,很多的技術(shù)經(jīng)理 、 技術(shù)總監(jiān)從骨子里非常的厭惡從北大青鳥(niǎo)出來(lái)的學(xué)生,對(duì)于他們開(kāi)設(shè)的一些課程也是相當(dāng)?shù)姆锤?,?dāng)時(shí)在西部世紀(jì)工作的時(shí)候,同組的就有和我一起上課的同班同學(xué),在他交了8000多元的學(xué)習(xí)費(fèi)用(總共的費(fèi)用接近1萬(wàn)多元)后,得到的僅僅只是西部世紀(jì)的一張?jiān)囉猛ㄖ獑?,而條件是必須無(wú)條件的為公司工作三個(gè)月!
這就是我在北大青鳥(niǎo)的學(xué)習(xí)經(jīng)歷,然而憤怒的不是這個(gè),卻是今天參加的面試經(jīng)歷,對(duì)照著自己的個(gè)人的工作經(jīng)歷我希望自己能夠成為一名培訓(xùn)部的老師,教給那些原來(lái)如我一樣的學(xué)生一些在實(shí)踐當(dāng)中有用的東西,而不是空洞的理論!所以我給ACCP投了自己的簡(jiǎn)歷,然而讓我卻又一次的遇到了那個(gè)欺騙過(guò)我的咨詢師,不過(guò)她的記憶力也是非常的好,一眼就認(rèn)出了我(當(dāng)然了我是曾經(jīng)給她帶來(lái)獎(jiǎng)金的人),在緊接著的面試過(guò)程中已經(jīng)變了味道,談?wù)摰脑掝}也不是具體項(xiàng)目技術(shù)的問(wèn)題,(不是我笑話她與她談?wù)摷夹g(shù)問(wèn)題根本就如同對(duì)牛彈琴)她顯然是一個(gè)沒(méi)有素質(zhì)的WOMAN,也可以肯定的是她根本沒(méi)有在外企工作過(guò)的經(jīng)歷,所以說(shuō)話的詞匯以及與其如同大街上的潑婦一般,可以想見(jiàn)她一定是一個(gè)被ACCP嚴(yán)重洗過(guò)腦的人,而且是屬于那種技術(shù)失敗的產(chǎn)品,她無(wú)法接受別的培訓(xùn)部的名字,一旦你提起別的培訓(xùn)部的某個(gè)老師的水平如何如何的好,她就如同一個(gè)快被點(diǎn)燃的鞭炮一般,兩眼充滿了憤怒!
然而讓我最終和她一般的沒(méi)有素質(zhì)的大罵的是她對(duì)于我辭職的評(píng)點(diǎn),我很納悶的是她在不知道一件事情的原因的情況下,可以講述自己的觀點(diǎn)!并且是帶著教育的口吻,實(shí)在是人才呀!這就是北大青鳥(niǎo)的"人才力量",對(duì)于這樣的白癡級(jí)別的任務(wù)的觀點(diǎn),我只好打斷,因?yàn)樗踔吝B我在的那個(gè)單位的名字都不知道?。?br />
實(shí)在是一場(chǎng)鬧劇,而她更像是個(gè)小丑,除了唧唧喳喳的重復(fù)一些"洗腦"的詞匯已經(jīng)不知道窗外的天氣了,可以預(yù)料北大青鳥(niǎo)的牌子必將會(huì)毀在這些個(gè)白癡的手中,世界需要白癡,那如同鮮花需要牛糞一樣,我們改變不了白癡的世界觀的,你能夠做的就是別被這臭烘烘的牛糞給熏臭了。
posted @ 2006-04-01 12:53 killvin| 編輯 收藏
[深入的思考] 為什么要采用java這個(gè)平臺(tái)?
從開(kāi)發(fā)項(xiàng)目的類別角度看java平臺(tái)
基于B/S結(jié)構(gòu)的系統(tǒng),在這個(gè)方向上的競(jìng)爭(zhēng)是激烈的,有專注于此的LAMP(Linux + Apache + Mysql + Php);也有剛剛興起的Rails(Ruby Frameworks)甚至是號(hào)稱快速開(kāi)發(fā)的ASP.NET;當(dāng)然了java在這個(gè)領(lǐng)域里的MVC框架數(shù)都數(shù)不完,比如Struts . Webwork等,然而即便是如此,選擇java作為開(kāi)發(fā)的理由也是不充分的,因?yàn)樵谶@個(gè)梯隊(duì)里java頂多排名最后。
基于C/S結(jié)構(gòu)的系統(tǒng),在這個(gè)方面java顯然沒(méi)有考慮周到,面對(duì)VB 、DELPHI、vc這些個(gè)如狼似虎的快速開(kāi)發(fā)IDE,JAVA實(shí)在是顯得異常的淡薄,即使你找到了一個(gè)可以匹敵這些個(gè)ide的工具,面對(duì)第三方的組件又會(huì)成為一大障礙,所以java在這個(gè)方面又一次的輸了。
從java所強(qiáng)調(diào)的特性角度看java平臺(tái)
java的重點(diǎn)是業(yè)務(wù)邏輯!(我以前也是如此堅(jiān)信不移)可是誰(shuí)有能夠說(shuō)別的語(yǔ)言不注重業(yè)務(wù)邏輯呢,業(yè)務(wù)邏輯只是一個(gè)抽象的概念,java只是依靠ejb提出了業(yè)務(wù)組件而已,其他的語(yǔ)言在實(shí)現(xiàn)業(yè)務(wù)邏輯的時(shí)候也可以包裝成POJO的形式,看來(lái)這個(gè)觀點(diǎn)也是失敗的。
java強(qiáng)調(diào)的是跨平臺(tái)的優(yōu)勢(shì)!這可以理解為初級(jí)的、商業(yè)的、忽悠人的詞匯,面對(duì)眾多動(dòng)態(tài)語(yǔ)言如Python,在若干平臺(tái)上的表現(xiàn),java又如何來(lái)強(qiáng)調(diào)自己這方面的優(yōu)勢(shì)呢?失敗
java支持分布式應(yīng)用的項(xiàng)目!可笑的言論,分布式根本不是值得炫耀的資本,在java之前的c/s項(xiàng)目中何嘗不是分布式的應(yīng)用呢?失敗
既然沒(méi)有了這些個(gè)優(yōu)勢(shì),我們看看java到底還剩下些什么?對(duì)了其實(shí)就是應(yīng)用服務(wù)器!然而看過(guò)J2EE WITHOUT EJB的讀者肯定知道Spring所希望達(dá)到的目的,也就是脫離應(yīng)用服務(wù)器概念上的J2EE體系實(shí)現(xiàn),既然在作者的眼里APPLICATION SERVER只不過(guò)是一個(gè)忽悠人的詞匯,那么任何項(xiàng)目都選擇java作為開(kāi)發(fā)的依據(jù)顯然就是自找苦吃,
那么什么情況下改選擇java作為開(kāi)發(fā)的平臺(tái)呢?
<1> 如果你真的遇到了大型的系統(tǒng)開(kāi)發(fā)任務(wù),恭喜你,你終于可以看到分布式對(duì)象、集群的優(yōu)勢(shì)了。
<2> 客戶是一個(gè)java的忠實(shí)fans或者是sun、ibm的金牌合作伙伴之類的,選擇java是不得已的,但記住并不能證明java是最好的實(shí)現(xiàn)方式
<3> 如果你只想關(guān)心業(yè)務(wù)邏輯的實(shí)現(xiàn),對(duì)于事務(wù)、緩存、查找等服務(wù)的實(shí)現(xiàn)沒(méi)有興趣的話,倒是不妨考慮采用ejb的形式,當(dāng)然前提是你不愿意在尋找合適的替代品的情況下。
<4> 如果項(xiàng)目迫切的尋找某種框架的支持,選擇java就是對(duì)的,你有眾多優(yōu)秀的、免費(fèi)的、可擴(kuò)展的、天才的框架可以選擇,更多的時(shí)候你是出于尷尬的境地,因?yàn)槿魏我粋€(gè)都讓你心動(dòng)、而這樣的選擇往往是最痛苦、和快樂(lè)的。
正確的選擇
<1>
條件: 如果項(xiàng)目?jī)H僅只是一個(gè)小型的網(wǎng)站系統(tǒng)
選擇: LAMP、Rails
<2>
條件: 項(xiàng)目規(guī)模中等
并且項(xiàng)目的時(shí)間比較緊,
項(xiàng)目可以架構(gòu)在windows的系統(tǒng)之上,
選擇: .Net? / Delphi
<3>
條件: 大型的系統(tǒng),有支持分布式對(duì)象、集群的要求;或者SUN / IBM的金牌合作伙伴 ; 想要尋找某種優(yōu)秀的框架來(lái)解決問(wèn)題
選擇: java是不二的選擇,可是我想問(wèn)一下,在現(xiàn)實(shí)中你能遇到這樣的項(xiàng)目嗎?
所以,從實(shí)際的角度出發(fā),我們面對(duì)的99%可能都是一些符合條件1,2的系統(tǒng),而選擇java實(shí)在是得不償失的。最后以一段Code Complete中的話來(lái)作為結(jié)束語(yǔ)
每個(gè)程序員都有很多的工具,但并不存在任何一個(gè)能夠適用于所有工作的工具,因地制宜的選擇正確工具是成為能有效編程的程序員的關(guān)鍵。
posted @ 2006-03-29 13:49 killvin| 編輯 收藏
作者簡(jiǎn)介
XincChen是Xtremework公司創(chuàng)始人.a自從.NET推出以來(lái),1他已使用.NET幫助很多行業(yè)的用戶開(kāi)發(fā)了體現(xiàn)其商業(yè)理念的軟件產(chǎn)品.aXincChen是.NET和EAI方面的專家,1他與Microsoft和Accenture等多家技術(shù)領(lǐng)先的公司合作,1為它們的客戶提供了優(yōu)秀的解決方案.a在工作之余,1他喜歡讀書(shū).c寫(xiě)書(shū).c以及靜靜地休息.aApress出版社的另一本書(shū)——《BizTalkc2002cDesigncandcImplementation》——也是出自他的筆下.aXincChen擁有哥倫比亞大學(xué)的統(tǒng)計(jì)學(xué)文科碩士學(xué)位,1現(xiàn)居國(guó)內(nèi),1正在籌建公司在北京的研發(fā)中心.a可通過(guò)xchen@Xtremework.com和作者取得聯(lián)系.
個(gè)人評(píng)論
這本書(shū)本來(lái)購(gòu)買(mǎi)時(shí)的期望值非常的高,想必是一本細(xì)數(shù).NET框架類的圖書(shū),結(jié)果卻大失所望,而這本書(shū)也就因?yàn)槠浼夹g(shù)上的薄弱而消弱了其價(jià)值的表現(xiàn)力,不過(guò)作為一本.NET入門(mén)級(jí)的圖書(shū)還是比較的合適,但在CSDN上竟然有四顆半的星的待遇實(shí)在不敢恭維。
而且作者的代碼顯然非常的粗造,竟然連起碼的業(yè)務(wù)級(jí)數(shù)據(jù)校驗(yàn)都沒(méi)有,在一些功能的分解上也是抹漿糊,可以想象作者并沒(méi)有深入的思考而僅僅是去實(shí)現(xiàn)功能而已,猜想這樣的框架很可能是作者對(duì)于以前工作的簡(jiǎn)單抽象而已。
整體上本書(shū)除了第一章應(yīng)用框架介紹 、 第二章應(yīng)用框架解析比較的出彩,尤其是創(chuàng)造性的提出了業(yè)務(wù)假設(shè)(Business assumption)的概念還比較的有深度,其他的章節(jié)只是對(duì)于其SAF框架的介紹,但在技術(shù)實(shí)現(xiàn)上只是對(duì)于.NET的若干相關(guān)服務(wù)的簡(jiǎn)單包裝而已,對(duì)于已經(jīng)在JAVA世界里的人來(lái)說(shuō),SAF框架其實(shí)就是Spring框架在.NET世界的簡(jiǎn)單實(shí)現(xiàn)版本,但相對(duì)于Spring的技術(shù)實(shí)力,作者還需要努力才行,不過(guò)作者顯然是.NET方面的高手,對(duì)于.NET世界提供的雜亂無(wú)章的服務(wù)特性以及服務(wù)的原理非常的清楚,這也難怪在這樣的平臺(tái)上再去"多此一舉"的開(kāi)發(fā)另外的框架,無(wú)論從技術(shù)上還是推廣上都非常的難!不過(guò)領(lǐng)略一下..NET的秀發(fā)也是多少有所收獲的 :)
再次強(qiáng)調(diào)這本書(shū)僅僅只能夠算作.NET方面的初級(jí)讀物,個(gè)人評(píng)星3.5 ,請(qǐng)朋友們謹(jǐn)慎購(gòu)買(mǎi)。
posted @ 2006-03-24 14:22 killvin| 編輯 收藏
wfc是構(gòu)建在B/S結(jié)構(gòu)上的流程定義工具
具備以下的功能
1> 實(shí)現(xiàn)了B/S結(jié)構(gòu)上的工作流定義工具(沒(méi)有看到同類型的產(chǎn)品)。
2> 流程定義格式與具體的工作流格式相分離,并可以在此基礎(chǔ)上實(shí)現(xiàn)其他的流程定義工具產(chǎn)品。
3> 采用了Buffalo(XML-RPC的javascript實(shí)現(xiàn))實(shí)現(xiàn)與后端Servlet的綁定。
4> 可以對(duì)具體的節(jié)點(diǎn)進(jìn)行屬性的配置(配置后的數(shù)據(jù)會(huì)被綁定為java的List自動(dòng)傳遞到后端)。
目前還需要改進(jìn)的
1> 修改目前工作流的圖標(biāo)(需要分支、狀態(tài)、合并這樣專業(yè)的圖標(biāo))
2> 解決瀏覽器的刷新問(wèn)題。
3> 增加線段的表現(xiàn)形式選項(xiàng)
4> 增加曲線的表現(xiàn)形式,尤其是在多線段的情況下要自動(dòng)調(diào)整為曲線的形式。
目前的WFC已經(jīng)被Michael Chen(buffalo的作者)收錄在其網(wǎng)站上!地址如下
http://demo.amowa.net/wfc
對(duì)于buffalo的關(guān)注早在作者剛發(fā)布的時(shí)候就已經(jīng)開(kāi)始了,起初不太了解buffalo的作用,然而在具體的工作中尋找基于XML-RPC協(xié)議的產(chǎn)品時(shí)突然明白了它的價(jià)值,不過(guò)說(shuō)簡(jiǎn)單一點(diǎn)buffalo是實(shí)現(xiàn)了基于javascript的對(duì)象的序列化以及反序列化工作。
posted @ 2006-03-21 17:58 killvin| 編輯 收藏
通用類圖書(shū)
卓越獎(jiǎng): Prefactoring by Ken Pugh (O'Reilly)
生產(chǎn)力獎(jiǎng):
Innovation Happens Elsewhere: Open Source as Business Strategy by Ron Goldman, Richard P. Gabriel (Morgan Kaufmann)
Producing Open Source Software: How to Run a Successful Free Software Project by Karl Fogel (O'Reilly)
The Art of Project Management by Scott Berkun (O'Reilly)
技術(shù)類圖書(shū)
卓越獎(jiǎng):Agile Web Development with Rails by Dave Thomas, David Hansson, Leon Breedt and Mike Clark (Pragmatic Bookshelf)
生產(chǎn)力獎(jiǎng):
Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries by Krzysztof Cwalina and Brad Abrams (Addison-Wesley)
Practical Common Lisp by Peter Seibel (Apress)
Why Programs Fail: A Guide to Systematic Debugging by Andreas Zeller (Morgan Kaufmann)
企業(yè)項(xiàng)目管理
卓越獎(jiǎng): WelcomRisk 2.6 (Welcom)
生產(chǎn)力獎(jiǎng):
Corticon Business Rules Management 4.0 (Corticon)
JBoss 2 Portal (JBoss)
Visual Studio Team System 2005 (Microsoft)
數(shù)據(jù)庫(kù)引擎和數(shù)據(jù)工具
卓越獎(jiǎng): Microsoft SQL Server 2005 (Microsoft)
生產(chǎn)力獎(jiǎng):
Berkeley DB 4.4 (Sleepycat Software)
Google Maps API 2005 (Google)
MySQL 5.0 (MySQL)
缺陷跟蹤,變更和配置管理
卓越獎(jiǎng): Perforce SCM 2005 (Perforce)
生產(chǎn)力獎(jiǎng):
FogBugz 4.0 (Fog Creek)
Guiffy SureMerge 7.0 (Guiffy Software)
JIRA 3.4 (Atlassian Software)
設(shè)計(jì)和建模工具
卓越獎(jiǎng):Lattix LDM 2.0 (Lattix)
生產(chǎn)力獎(jiǎng):
Borland Together 2006 for Eclipse (Borland)
Enterprise Architect 6.0 (Sparx Systems)
MindManager Pro 6.0 (Mindjet)
開(kāi)發(fā)環(huán)境
卓越獎(jiǎng): Visual Studio Team System 2005 (Microsoft)
生產(chǎn)力獎(jiǎng):
Eclipse SDK 3.1 (Eclipse.org)
IntelliJ IDEA 5.0 (JetBrains)
Komodo 3.5 (ActiveState)
類庫(kù)、框架和組建
卓越獎(jiǎng): .NET Framework 2.0 (Microsoft)
生產(chǎn)力獎(jiǎng):
Dundas Chart for .NET 5.0 (Dundas Software)
Qt 4.0 (Trolltech)
Spring Framework 1.2.6 (SpringFramework.org)
移動(dòng)開(kāi)發(fā)工具
卓越獎(jiǎng): Crossfire 5.6 (AppForge)
生產(chǎn)力獎(jiǎng):
Carbide.c++ Express (Nokia)
Flash Lite 2.0 (Adobe)
NetBeans IDE 4.1 (Sun Microsystems)
項(xiàng)目質(zhì)量管理
卓越獎(jiǎng): Rally 5.6 (Rally Software Development)
生產(chǎn)力獎(jiǎng):
CollabNet Enterprise Edition with Project Dashboard/Task Management 2005 (CollabNet)
QACenter Enterprise Edition 5.1 (Compuware)
TargetProcess Suite 1.4 (TargetProcess)
安全工具
卓越獎(jiǎng): Elemental Compliance System 1.4 (Elemental)
生產(chǎn)力獎(jiǎng):
CodeAssure 2.0 (Secure Software)
DevPartner SecurityChecker 1.0 (Compuware)
Fortify Security Tester 1.0 (Fortify)
測(cè)試工具
卓越獎(jiǎng):VMTN Subscription 2005 (VMware)
生產(chǎn)力獎(jiǎng):
Agitator 3.0 (Agitar Software)
AQtime 4.7 (AutomatedQA)
Clover 1.3 (Cenqua)
實(shí)用程序
卓越獎(jiǎng):Camtasia Studio 3.0 (TechSmith)
生產(chǎn)力獎(jiǎng):
DevPartner Studio 8 (Compuware)
Fog Creek Copilot 1.2 (Fog Creek Software)
ReSharper 1.5 (JetBrains)
Web開(kāi)發(fā)工具
卓越獎(jiǎng): Rails 1.0 (rubyonrails.org)
生產(chǎn)力獎(jiǎng):
JBoss Application Server 4x (JBoss)
Macromedia Studio 8 2005 (Adobe)
Zend Studio - Enterprise Edition 5.0 (Zend)
名人堂產(chǎn)品獲獎(jiǎng)?wù)?
?Visual Studio Professional Edition (Microsoft)
感慨
??? MS在這次的JOLT中屢獲殊榮,深思。。。
posted @ 2006-03-19 09:32 killvin| 編輯 收藏
很久都不罵人了,可是一不留心又看到了他寫(xiě)了惡心文章,實(shí)在是讓人憤慨!這位板橋里人的"大名"是從透明的blog上知道的,首先就是感覺(jué)這個(gè)人的腦子有點(diǎn)問(wèn)題!不去評(píng)論他發(fā)布的那個(gè)所謂的框架,就看看他寫(xiě)的一些文章就足以知道這個(gè)人腦袋非常的混亂,在這樣混亂的情況下寫(xiě)出來(lái)的文章也就可想而知了,最近這位所謂的"大俠"又開(kāi)始害人了
你還在用if else嗎?- http://www.jdon.com/artichect/ifelse.htm
面向過(guò)程設(shè)計(jì)和面向?qū)ο笤O(shè)計(jì)的主要區(qū)別是:是否在業(yè)務(wù)邏輯層使用冗長(zhǎng)的if else判斷。如果你還在大量使用if else,當(dāng)然,界面表現(xiàn)層除外,即使你使用Java/C#這樣完全面向?qū)ο蟮恼Z(yǔ)言,也只能說(shuō)明你的思維停留在傳統(tǒng)的面向過(guò)程語(yǔ)言上。
-我很納悶了作者怎么可以從是否使用if else來(lái)判斷一個(gè)設(shè)計(jì)是否符合OO特性呢?我們看到的if else屬于語(yǔ)言這個(gè)層次的東西,而if else僅僅是完成邏輯判斷的語(yǔ)句;如果說(shuō)作者的這個(gè)觀點(diǎn)成立的話,java、c#的語(yǔ)言發(fā)明者應(yīng)該早就明白或者預(yù)測(cè)到if else 的"不OO"的特性,也會(huì)考慮到在語(yǔ)言層面刪除這樣的邏輯判斷語(yǔ)句,但事實(shí)呢?發(fā)明者非但沒(méi)有刪除相反其他語(yǔ)言的發(fā)明者也一起發(fā)明了if else語(yǔ)句?!難道是大師們錯(cuò)了?
還是以大家熟悉的論壇帖子為例子,如ForumMessage是一個(gè)模型,但是實(shí)際中帖子分兩種性質(zhì):主題貼(第一個(gè)根貼)和回帖(回以前帖子的帖子),這里有一個(gè)樸素的解決方案:
建立一個(gè)ForumMessage,然后在ForumMessage加入isTopic這樣判斷語(yǔ)句,注意,你這里一個(gè)簡(jiǎn)單屬性的判斷引入,可能導(dǎo)致你的程序其他地方到處存在if else 的判斷。
如果我們改用另外一種分析實(shí)現(xiàn)思路,以對(duì)象化概念看待,實(shí)際中有主題貼和回帖,就是兩種對(duì)象,但是這兩種對(duì)象大部分是一致的,因此,我將ForumMessage設(shè)為表達(dá)主題貼;然后創(chuàng)建一個(gè)繼承ForumMessage的子類ForumMessageReply作為回帖,這樣,我在程序地方,如Service中,我已經(jīng)確定這個(gè)Model是回帖了,我就直接下溯為ForumMessageReply即可,這個(gè)有點(diǎn)類似向Collection放入對(duì)象和取出時(shí)的強(qiáng)制類型轉(zhuǎn)換。通過(guò)這個(gè)手段我消滅了以后程序中if else的判斷語(yǔ)句出現(xiàn)可能。
-作者在這里似乎列舉了一個(gè)例子,可是對(duì)于帖子和回帖這樣簡(jiǎn)單的問(wèn)題,只要遵守OO的設(shè)計(jì)師都會(huì)抽象出一個(gè)帖子的父類,然而這又能說(shuō)明什么呢?在具體的業(yè)務(wù)邏輯中難道你不判斷傳遞過(guò)來(lái)的對(duì)象的類別?(現(xiàn)在主題貼與回帖的處理方法是不同的),同樣你無(wú)法避免在具體的編碼中使用if else的可能?!
最后總結(jié):將if else用在小地方還可以,如簡(jiǎn)單的數(shù)值判斷;但是如果按照你的傳統(tǒng)習(xí)慣思維,在實(shí)現(xiàn)業(yè)務(wù)功能時(shí)也使用if else,那么說(shuō)明你的思維可能需要重塑,你的編程經(jīng)驗(yàn)越豐富,傳統(tǒng)過(guò)程思維模式就容易根深蒂固,想靠自己改變很困難;建議接受專業(yè)頭腦風(fēng)暴培訓(xùn)。
用一句話總結(jié):如果你做了不少系統(tǒng),很久沒(méi)有使用if else了,那么說(shuō)明你可能真正進(jìn)入OO設(shè)計(jì)的境地了。(這是本人自己發(fā)明的實(shí)戰(zhàn)性的衡量考核標(biāo)準(zhǔn))。
-顯然作者并不是去討論if else的語(yǔ)言問(wèn)題,而是為自己的"洗腦培訓(xùn)"打廣告!并講這樣的問(wèn)題上升到設(shè)計(jì)模式、禪的境界,可謂是煞費(fèi)苦心呀,沒(méi)有人說(shuō)設(shè)計(jì)模式不好也沒(méi)有人懷疑禪的境界的高深,但不是作者這樣的人靠讀一兩篇文章或者發(fā)布個(gè)所謂的"毫無(wú)實(shí)際意義"的框架就可以領(lǐng)悟到的,還是那句話:長(zhǎng)得丑不要緊,不要出來(lái)嚇人!不過(guò)我還要補(bǔ)充一句就是,不懂不要緊,不要亂說(shuō)免得害人(因?yàn)槲覀兌贾罎妺D罵街的道理,雖然沒(méi)文化但確實(shí)能夠帶來(lái)眼球效應(yīng))。
posted @ 2006-03-10 11:49 killvin| 編輯 收藏
本來(lái)以為是Maxthon的問(wèn)題(在鼠標(biāo)單擊的時(shí)候會(huì)關(guān)閉一些窗口,并且是隨機(jī)的??。┻€就這樣的問(wèn)題給作者寫(xiě)了一封信?汗。。。經(jīng)過(guò)仔細(xì)的尋找原因,原來(lái)是自己的鼠標(biāo)的問(wèn)題(這個(gè)鼠標(biāo)跟了我快7年了,Logitech最好的滾軸鼠標(biāo),要300多塊大洋)有點(diǎn)舍不得,又沒(méi)有辦法,該下崗了,一同下崗的也許還有我的鍵盤(pán)(TCL的手感級(jí)差!:( )
不過(guò)為了找原因我倒是廢了一番周折,下載和試用了N多的瀏覽器,也看了很多網(wǎng)上的評(píng)論對(duì)比文章,現(xiàn)在主流的瀏覽器主要就是Opera , Firefox, Maxthon , GreenBrowser , MyIE , TheWorld 等,然而在資源的利用率上這些個(gè)產(chǎn)品都非常的讓人失望,難道就沒(méi)有一款適合于程序員的胃口的瀏覽器?!
可喜的是偶發(fā)現(xiàn)了GOSURF這款瀏覽器,在眾多的瀏覽器中它的內(nèi)存占用率是最低的,而且它的作者似乎在這方面也是煞費(fèi)苦心,"一味"的強(qiáng)調(diào)速度,甚至對(duì)于鼠標(biāo)手這個(gè)及其流行的功能的加入也是非常的謹(jǐn)慎,可以看出作者是個(gè)很有個(gè)性的程序員,值得期待!
如果你和我一樣對(duì)資源的利用率近乎苛刻,可以考慮這樣的一款產(chǎn)品 http://gosurfbrowser.com/?ln=cn
posted @ 2006-03-07 17:42 killvin| 編輯 收藏
http://www-128.ibm.com/developerworks/cn/java/j-junit4.html
JUnit 是 Java? 語(yǔ)言事實(shí)上的 標(biāo)準(zhǔn)單元測(cè)試庫(kù)。JUnit 4 是該庫(kù)三年以來(lái)最具里程碑意義的一次發(fā)布。它的新特性主要是通過(guò)采用 Java 5 中的標(biāo)記(annotation)而不是利用子類、反射或命名機(jī)制來(lái)識(shí)別測(cè)試,從而簡(jiǎn)化測(cè)試。在本文中,執(zhí)著的代碼測(cè)試人員 Elliotte Harold 以 JUnit 4 為例,詳細(xì)介紹了如何在自己的工作中使用這個(gè)新框架。注意,本文假設(shè)讀者具有 JUnit 的使用經(jīng)驗(yàn)。
JUnit 由 Kent Beck 和 Erich Gamma 開(kāi)發(fā),幾乎毫無(wú)疑問(wèn)是迄今所開(kāi)發(fā)的最重要的第三方 Java 庫(kù)。正如 Martin Fowler 所說(shuō),“在軟件開(kāi)發(fā)領(lǐng)域,從來(lái)就沒(méi)有如此少的代碼起到了如此重要的作用”。JUnit 引導(dǎo)并促進(jìn)了測(cè)試的盛行。由于 JUnit,Java 代碼變得更健壯,更可靠,bug 也比以前更少。JUnit(它本身的靈感來(lái)自 Smalltalk 的 SUnit)衍生了許多 xUnit 工具,將單元測(cè)試的優(yōu)勢(shì)應(yīng)用于各種語(yǔ)言。nUnit (.NET)、pyUnit (Python)、CppUnit (C++)、dUnit (Delphi) 以及其他工具,影響了各種平臺(tái)和語(yǔ)言上的程序員的測(cè)試工作。
然而,JUnit 僅僅是一個(gè)工具而已。真正的優(yōu)勢(shì)來(lái)自于 JUnit 所采用的思想和技術(shù),而不是框架本身。單元測(cè)試、測(cè)試先行的編程和測(cè)試驅(qū)動(dòng)的開(kāi)發(fā)并非都要在 JUnit 中實(shí)現(xiàn),任何比較 GUI 的編程都必須用 Swing 來(lái)完成。JUnit 本身的最后一次更新差不多是三年以前了。盡管它被證明比大多數(shù)框架更健壯、更持久,但是也發(fā)現(xiàn)了 bug;而更重要的是,Java 不斷在發(fā)展。Java 語(yǔ)言現(xiàn)在支持泛型、枚舉、可變長(zhǎng)度參數(shù)列表和注釋,這些特性為可重用的框架設(shè)計(jì)帶來(lái)了新的可能。
JUnit 的停滯不前并沒(méi)有被那些想要廢棄它的程序員所打敗。挑戰(zhàn)者包括 Bill Venners 的 Artima SuiteRunner 以及 Cedric Beust 的 TestNG 等。這些庫(kù)有一些可圈可點(diǎn)的特性,但是都沒(méi)有達(dá)到 JUnit 的知名度和市場(chǎng)占有份額。它們都沒(méi)有在諸如 Ant、Maven 或 Eclipse 之類的產(chǎn)品中具有廣泛的開(kāi)箱即用支持。所以 Beck 和 Gamma 著手開(kāi)發(fā)了一個(gè)新版本的 JUnit,它利用 Java 5 的新特性(尤其是注釋)的優(yōu)勢(shì),使得單元測(cè)試比起用最初的 JUnit 來(lái)說(shuō)更加簡(jiǎn)單。用 Beck 的話來(lái)說(shuō),“JUnit 4 的主題是通過(guò)進(jìn)一步簡(jiǎn)化 JUnit,鼓勵(lì)更多的開(kāi)發(fā)人員編寫(xiě)更多的測(cè)試?!盝Unit 4 盡管保持了與現(xiàn)有 JUnit 3.8 測(cè)試套件的向后兼容,但是它仍然承諾是自 JUnit 1.0 以來(lái) Java 單元測(cè)試方面最重大的改進(jìn)。
注意:該框架的改進(jìn)是相當(dāng)前沿的。盡管 JUnit 4 的大輪廓很清晰,但是其細(xì)節(jié)仍然可以改變。這意味著本文是對(duì) JUnit 4 搶先看,而不是它的最終效果。
posted @ 2006-03-05 13:10 killvin| 編輯 收藏
在這個(gè)暖暖的午后享受著陽(yáng)光的溫暖的同時(shí),聽(tīng)著CUSCO 的專輯實(shí)在是一種享受,我喜歡那種寧?kù)o的音樂(lè),因?yàn)樗鼛Ыo你的除了純凈還是純凈。。。。
不想被任何的人打擾,城市的喧鬧讓自己的思想變得復(fù)雜,而唯獨(dú)音樂(lè)才能夠真正的喚醒你心靈深處的東西,
posted @ 2006-03-04 13:23 killvin| 編輯 收藏
標(biāo)準(zhǔn)答案是:在web.xml中配置ActionServlet的config參數(shù),在經(jīng)過(guò)大腦短暫的思考后我斷定我的回答并沒(méi)有錯(cuò)!
誰(shuí)說(shuō)一定要配置這樣的參數(shù)?那只是ActionServlet的"一廂情愿",如果有一天Struts不高興了,將尋找配置文件的策略更改成:從classpath尋找,你認(rèn)為我說(shuō)的答案還是錯(cuò)誤的嗎?
所以我想說(shuō)這樣的面試問(wèn)題是弱智的,一個(gè)人不可能知道所有的一切,對(duì)于現(xiàn)在這個(gè)社會(huì)如此眾多的框架產(chǎn)品你怎么可能光靠某個(gè)問(wèn)題就斷定一個(gè)人的能力呢?
其實(shí)如果他可以這樣問(wèn):你認(rèn)為配置文件的讀取策略可以有多少種?或者如果是你設(shè)計(jì)Struts你會(huì)如何解決多配置文件的問(wèn)題?這樣啟發(fā)式的詢問(wèn)更會(huì)激起面試者的興趣,難道這些個(gè)所謂的技術(shù)總監(jiān)不該反思一下?
當(dāng)然,不是僅僅一個(gè)這樣的事件引起了自己點(diǎn)憤怒,而是很多很多的所謂的技術(shù)專家的弱智問(wèn)題,不知道磨滅了多少人的熱情!如果你也是遇到了這樣的尷尬,索性問(wèn)他一個(gè)自己非常另類的問(wèn)題-比如"內(nèi)部類如何訪問(wèn)外部類的對(duì)象?"
該死,請(qǐng)不要再問(wèn)我弱智的問(wèn)題了
posted @ 2006-03-03 17:53 killvin| 編輯 收藏
在OSWorkflow中最讓人惱火的就是它的接口定義!我會(huì)就這些接口的混亂展開(kāi)一系列的分析,今天先說(shuō)說(shuō)Configuration接口
偶繼承了它的Configuration接口
import com.company.engine.workflow.store.IWorkFlowStore;
import com.opensymphony.workflow.StoreException;
import com.opensymphony.workflow.config.Configuration;
import com.opensymphony.workflow.spi.WorkflowStore;
public interface IConfiguration extends Configuration
{
/**
* @deprecated getIWorkflowStore()
*/
WorkflowStore getWorkflowStore() throws StoreException;
/**
* return WorkFlowStore which implements the interface of IWorkFlowStore
* @return
* @throws StoreException
*/
IWorkFlowStore getIWorkflowStore() throws StoreException;
}
你可能奇怪我為何要繼承它的接口(肯定是Bad smell),原因如下,
IWorkFlowStore 接口定義
import com.opensymphony.workflow.StoreException;
import com.opensymphony.workflow.spi.Step;
import com.opensymphony.workflow.spi.WorkflowEntry;
import com.opensymphony.workflow.spi.WorkflowStore;
public interface IWorkFlowStore extends WorkflowStore
{
public Step createCurrentStep(WorkflowEntry _entry , Step _step) throws StoreException;
}
WorkflowStore接口定義
/**
* Persists a step with the given parameters.
*
* @param entryId The workflow instance id.
* @param stepId the ID of the workflow step associated with this new
* Step (not to be confused with the step primary key)
* @param owner the owner of the step
* @param startDate the start date of the step
* @param status the status of the step
* @param previousIds the previous step IDs
* @return a representation of the workflow step persisted
*/
public Step createCurrentStep(long entryId, int stepId, String owner, Date startDate, Date dueDate, String status, long[] previousIds) throws StoreException;
看到了吧?
其實(shí)我只是希望在createCurrentStep時(shí)按照OO的方法執(zhí)行,而不是傳遞那些"Bad Smell"的參數(shù),而OSWorkflow中的WorkflowStore是需要Configuration來(lái)獲取的,此時(shí)為了增加一個(gè)看似合理的方法,需要分別繼承Configuration與WorkflowStore;這還沒(méi)有完,你需要實(shí)現(xiàn)一個(gè)Configuration實(shí)現(xiàn)??!
import com.company.engine.workflow.store.IWorkFlowStore;
import com.opensymphony.workflow.StoreException;
import com.opensymphony.workflow.config.DefaultConfiguration;
import com.opensymphony.workflow.spi.WorkflowStore;
public class DefaultIConfiguration extends DefaultConfiguration implements IConfiguration
{
public static DefaultIConfiguration INSTANCE = new DefaultIConfiguration();
private transient IWorkFlowStore store = null;
/**
* @deprecated getIWorkflowStore()
*/
public WorkflowStore getWorkflowStore() throws StoreException
{
return null;
}
public IWorkFlowStore getIWorkflowStore() throws StoreException
{
if (store == null)
{
String clazz = getPersistence();
try
{
store = (IWorkFlowStore) Class.forName(clazz).newInstance();
}
catch (Exception ex)
{
throw new StoreException("Error creating store", ex);
}
store.init(getPersistenceArgs());
}
return store;
}
}
總結(jié)
1。OSWorkflow與WorkflowStore接口的關(guān)系比較的微妙,它需要借助于Configuration接口的實(shí)現(xiàn)來(lái)獲取到實(shí)際的WorkflowStore對(duì)象。
2。由于這樣的一種微妙關(guān)系,對(duì)WorkflowStore接口的擴(kuò)展必將連帶著需要擴(kuò)展Configuration接口,而產(chǎn)生這樣的"果凍效應(yīng)"的罪魁禍?zhǔn)拙褪怯捎赪orkflowStore接口與Configuration接口耦合的太緊。
3。OSWorkflow并沒(méi)有很好的遵守OO的設(shè)計(jì)規(guī)則,尤其在它的參數(shù)傳遞上,非常的差!
posted @ 2006-03-02 21:04 killvin| 編輯 收藏
版本 0.11
已經(jīng)完成
1。完成了接口1 和接口2 的方法
2。完成接口3的默認(rèn)實(shí)現(xiàn)
3。完成事務(wù)回滾的實(shí)現(xiàn)方法-等待測(cè)試
未完成
1。接口3的注冊(cè)與實(shí)例化解決方案
2。應(yīng)用的并發(fā)訪問(wèn)問(wèn)題以及解決數(shù)據(jù)的臟讀問(wèn)題
3。與具體的某個(gè)應(yīng)用掛接并測(cè)試
-事務(wù)的回滾
OSWorkFlow的事務(wù)回滾是依靠WorkflowContext這個(gè)接口來(lái)實(shí)現(xiàn)的,在New出某個(gè)WorkFlow的時(shí)候需要聲明WorkflowContext的實(shí)現(xiàn)類,一般會(huì)采用uper.context = new GearWheelWorkFlowContext(_caller);方法
比如這樣實(shí)現(xiàn):
public GearWheelWorkFlow(String _caller)
{
super.context = new GearWheelWorkFlowContext(_caller);
}
但OSWorkFlow的WorkflowContext的默認(rèn)實(shí)現(xiàn)BasicWorkFlowContext中根本沒(méi)有實(shí)現(xiàn)setRollbackOnly方法,也就沒(méi)有了參考的可能
再看看這個(gè)接口的其他實(shí)現(xiàn)類也都是建立在JTA這樣的跨Session的事務(wù)服務(wù)上,比如它的EJB的實(shí)現(xiàn)也是要調(diào)用容器提供的JTA實(shí)現(xiàn)才行!而JTA的實(shí)現(xiàn)比如要JNDI到數(shù)據(jù)庫(kù)池,此時(shí)的應(yīng)用光JTA+JNDI就已經(jīng)宣布 -這樣的例子必須生存在應(yīng)用服務(wù)器的環(huán)境下??!
可是,我不死心,我記得Hibernate可以實(shí)現(xiàn)本地事務(wù),也就是依靠JDBC本身的事務(wù)處理能力,而要實(shí)現(xiàn)這樣的功能就需要在數(shù)據(jù)庫(kù)連接的獲取上下一些功夫,也就是要保證回滾的數(shù)據(jù)庫(kù)連接必須是獲取時(shí)的那個(gè)連接,而存儲(chǔ)連接就成了一個(gè)需要首先解決的問(wèn)題。
解決數(shù)據(jù)庫(kù)連接的存儲(chǔ)問(wèn)題
目前存儲(chǔ)數(shù)據(jù)庫(kù)連接除了依靠靜態(tài)類外,還有一個(gè)通用的方法ThreadLocal類,這樣獲取數(shù)據(jù)庫(kù)連接的方法寫(xiě)成了如下的形式:
package com.company.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
public class DB2ConnectFactory
{
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(DB2ConnectFactory.class);
private static ThreadLocal threadLocal = new ThreadLocal();
//~
private Connection connect = null;
private Statement state = null;
private ResultSet result = null;
private boolean closeConnWhenDone = false;
//~
private String url = "jdbc:db2:WORKFLOW";
private String user = "";
private String password = "";
private String driverClassName = "COM.ibm.db2.jdbc.app.DB2Driver";
public DB2ConnectFactory() throws SQLException
{
this.init();
}
/**
* 獲取數(shù)據(jù)庫(kù)連接
* @return
* @throws SQLException
*/
public Connection getConn() throws SQLException
{
return (Connection)threadLocal.get();
}
/**
* 初始化數(shù)據(jù)庫(kù),并在緩沖中注冊(cè)數(shù)據(jù)庫(kù)連接
* @throws SQLException
*/
private void init() throws SQLException
{
try
{
// Get connect object
Class.forName(driverClassName);
closeConnWhenDone = true;
connect = DriverManager.getConnection(url, user, password);
state = connect.createStatement();
//Register the connection object in the threadlocal
threadLocal.set(connect);
}
catch (Exception e)
{
e.printStackTrace();
throw new SQLException(e.getMessage());
}
}
}
解決事務(wù)回滾
剛才說(shuō)了需要實(shí)現(xiàn)WorkflowContext接口
package com.company.engine.workflow;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.log4j.Logger;
import com.company.common.DB2ConnectFactory;
import com.opensymphony.workflow.WorkflowContext;
public class GearWheelWorkFlowContext implements WorkflowContext
{
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(GearWheelWorkFlowContext.class);
private static ThreadLocal threadLocal = new ThreadLocal();
// ~ Instance fields
// ////////////////////////////////////////////////////////
private String caller;
// ~ Constructors
// ///////////////////////////////////////////////////////////
public GearWheelWorkFlowContext(String caller)
{
this.caller = caller;
}
// ~ Methods
// ////////////////////////////////////////////////////////////////
public String getCaller()
{
return this.caller;
}
/**
* Tranaction : Set Roll back
* @throws SQLException
*/
public void setRollbackOnly()
{
Connection connect = null;
try
{
DB2ConnectFactory factory = new DB2ConnectFactory();
connect = factory.getConn();
if(connect != null) connect.rollback();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.clostConnection(connect);
}
}
private void clostConnection(Connection connect)
{
try
{
if(connect != null) connect.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
總結(jié)
1。我們可以看到由于接口中setRollbackOnly沒(méi)有異常的聲明,方法中即使拋出了異常也要自己"忍了"!看來(lái)良好的接口聲明其實(shí)是非常重要的。
2。而且需要重載原來(lái)JDBCWorkflow 中的cleanup方法,將其中的代碼屏蔽掉!數(shù)據(jù)庫(kù)的關(guān)閉放在了setRollbackOnly訪訪的finally中,原因就是由于我們要統(tǒng)一的管理數(shù)據(jù)庫(kù)連接所引發(fā)的,我們不能夠在WorkFlowStore的每一個(gè)方法執(zhí)行完畢后就關(guān)閉連接,因?yàn)檫@樣的話你根本沒(méi)有了事務(wù)回滾的可能,所以此時(shí)的連接需要在WorkflowContext中來(lái)處理。
感觸
OSWorkFlow的實(shí)現(xiàn)方法并不是像網(wǎng)上所說(shuō)的那樣的優(yōu)秀和文雅,更像是一個(gè)未完成任務(wù)的"半成品",Heni被網(wǎng)上鼓吹為大牛,但一個(gè)不寫(xiě)注釋和文檔的人,根本稱不上什么大牛!
OSWorkFlow更多的是實(shí)現(xiàn)了一個(gè)微內(nèi)核,而它的用戶模式是與OSUser這樣的框架耦合的(偶已經(jīng)將這樣的耦合打開(kāi)了,也就是接口3的定義),它的相關(guān)數(shù)據(jù)是與PropertySet框架耦合的(也就是接口2的定義),而且采用OSWorkFlow要經(jīng)過(guò)很原始的修改(比如我實(shí)現(xiàn)了DB2下的WorkFlowStore的實(shí)現(xiàn))。
不過(guò)也好即使以后不采用OSWorkFlow,自己實(shí)現(xiàn)一個(gè)這樣的引擎也應(yīng)該沒(méi)有什么問(wèn)題的,有時(shí)間了我倒是很想看看別的工作流的產(chǎn)品。
posted @ 2006-03-02 21:03 killvin| 編輯 收藏
1。應(yīng)用接口 Application Interface
--interface1 工作流自身提供的服務(wù)接口
--interface2 工作流與應(yīng)用之間的接口(主要是提供相關(guān)數(shù)據(jù)的調(diào)用接口)
2。擴(kuò)展接口 PlugIn Interface
--interface3 工作流與組織機(jī)構(gòu)之間的接口
--interface4 工作流與其他工作流之間的接口
將接口劃分成應(yīng)用接口與擴(kuò)展接口主要是依據(jù)工作流與相關(guān)應(yīng)用的調(diào)用關(guān)系,比如工作流與組織機(jī)構(gòu)之間,是工作流調(diào)用組織機(jī)構(gòu)中的人員信息,所以主動(dòng)者是WORKFLOW、被動(dòng)方是組織機(jī)構(gòu),所以應(yīng)該采用擴(kuò)展接口來(lái)實(shí)現(xiàn)
在擴(kuò)展接口上應(yīng)該采用Adapter模式,從而使工作流不局限于某個(gè)特定的實(shí)現(xiàn)
目前的進(jìn)展
0。Application Interface接口已經(jīng)基本實(shí)現(xiàn)了
PlugIn Interface接口目前基本完工,但OSWorkflow的實(shí)現(xiàn)實(shí)在是非常的丑陋,需要更改的地方太多,而且對(duì)于Interface3不可以使用它采用的User / Group模型(而且它使用了OSUser這個(gè)框架,對(duì)于多數(shù)的應(yīng)用程序基本可以說(shuō)不適合,而且它的User類竟然是Final ?!而且我發(fā)現(xiàn)它的很多類的屬性都是Protected!也就是說(shuō)除了他們自己根本沒(méi)有辦法擴(kuò)展,即使擴(kuò)展也是很丑陋的方式)
1?,F(xiàn)在最大的問(wèn)題是它的WorkStore接口的擴(kuò)展,我采用DB2的方式實(shí)現(xiàn)了它的接口,但這樣的方式會(huì)與DB2綁定在一起,如果自己寫(xiě)實(shí)現(xiàn)就要根據(jù)不同的DB采用不同的SQL語(yǔ)言-也就是不同的方言策略?!而且考慮到性能估計(jì)不是什么好主意,看來(lái)明天需要更換成HibernateWorkStore的形式,這樣工作流的持久層接口將工作在Hibernate之上,看來(lái)很完美的解決了這個(gè)問(wèn)題。
2。而且我擴(kuò)展了它的PropertySet,使其不再依靠JNDI尋找DataSource,而是通過(guò)嵌入在程序內(nèi)部采用JDBC的形式尋找數(shù)據(jù)庫(kù)連接,這樣我就不必為了驗(yàn)證一個(gè)問(wèn)題去建立那該死的數(shù)據(jù)庫(kù)緩沖池了(而且JNDI的形式也就不可避免的要用到容器,太重了?。?BR>
3。我編寫(xiě)了UserGroupCondition的實(shí)現(xiàn)類,這個(gè)類的作用就是調(diào)用Interface3的方法,從而判斷某個(gè)用戶是否屬于某個(gè)組(現(xiàn)在的做法是讓W(xué)orkStore實(shí)現(xiàn)Interface3的偷懶辦法,但很亂,看來(lái)還是要寫(xiě)一個(gè)Adapter去實(shí)現(xiàn)interface3才對(duì)?。?BR>
4。目前工作流引擎的工廠類已經(jīng)實(shí)現(xiàn)完工并測(cè)試通過(guò)。
用了近一個(gè)月的時(shí)間完成了這些工作,看起來(lái)很少但是基本上大量的時(shí)間花費(fèi)在熟悉工作流規(guī)范、WFMC標(biāo)準(zhǔn)、以及學(xué)習(xí)和擴(kuò)展OSWorkflow接口上,不過(guò)對(duì)OSWorkflow的實(shí)現(xiàn)基本上掌握了,如果拋開(kāi)OSWorkflow自己也可以采用自己的方式去實(shí)現(xiàn),或者會(huì)考慮使用Spring的方式(Interface3的Adapter不行就采用Spring實(shí)現(xiàn))。
BTW:
OSWorkflow的實(shí)現(xiàn)其實(shí)比較的丑陋!而且編碼根本沒(méi)有什么規(guī)范,接口的定義也是天馬行空,看來(lái)Heni除了他的大嘴外應(yīng)該好好的提高自己的技術(shù)修養(yǎng)。-實(shí)在不敢恭維這位"大師"的編碼水平!
posted @ 2006-03-02 21:03 killvin| 編輯 收藏
在Workflow事務(wù)回滾中遇到了問(wèn)題,是這樣的
DB2ConnectFactory 中g(shù)etConn方法
/**
* 獲取數(shù)據(jù)庫(kù)連接
* @return
* @throws SQLException
*/
public Connection getConn() throws SQLException
{
Object obj = threadLocal.get();
if(obj == null)
{
this.initFactoryStack();
}else
{
connect = (Connection)obj;
}
connect.setAutoCommit(false); //事務(wù)的回滾必須建立在將Commit狀態(tài)為False下,默認(rèn)是true
logger.debug("Get connect from factory - " + connect.hashCode());
return connect;
}
AbstractWorkflow 的doAction()方法
try {
//transition the workflow, if it wasn't explicitly finished, check for an implicit finish
if (!transitionWorkflow(entry, currentSteps, store, wf, action, transientVars, inputs, ps)) {
checkImplicitFinish(id);
}
} catch (WorkflowException e) {
context.setRollbackOnly(); // 這里調(diào)用WorkContext對(duì)象的setRollbackOnly()方法,執(zhí)行事務(wù)的回滾
throw e;
}
GearWheelWorkFlowContext 的setRollbackOnly方法
/**
* Tranaction : Set Roll back
* @throws SQLException
*/
public void setRollbackOnly()
{
logger.debug("Context execute setRollbackOnly() !!");
Connection connect = null;
try
{
DB2ConnectFactory factory = new DB2ConnectFactory();
connect = factory.getConn();
logger.debug("Context get connect " + connect.hashCode());
if(connect != null) connect.rollback();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.clostConnection(connect); //這里將關(guān)閉數(shù)據(jù)庫(kù)連接
}
}
可是這是"異常"情況下的處理流程,如果正常執(zhí)行呢?
剛開(kāi)始我想寫(xiě)在CleanUp()方法里,但又一想不行,因?yàn)檎?zhí)行的流程需要做兩個(gè)工作
1。將Commit狀態(tài)更新為true,并提交連接
2。關(guān)閉數(shù)據(jù)庫(kù)連接
關(guān)鍵就是關(guān)閉數(shù)據(jù)庫(kù)的連接在哪里寫(xiě)?!現(xiàn)在寫(xiě)在CleanUp()不合適,因?yàn)槊恳粋€(gè)WorkStore的方法都要默認(rèn)(程序已經(jīng)寫(xiě)死了,我可不想重載它的所有的方法?。。┑年P(guān)閉數(shù)據(jù)庫(kù)連接!
仔細(xì)的分析了一下,其實(shí)有兩個(gè)方法可以做到
1。編寫(xiě)Proxy類
2。重載所有AbstractWorkflow中設(shè)計(jì)到事務(wù)的方法,(本來(lái)可以重載transitionWorkflow但是方法的類型卻為private?!)在它的方法下增加一個(gè)"提交"的方法。比如這樣
try {
//transition the workflow, if it wasn't explicitly finished, check for an implicit finish
if (!transitionWorkflow(entry, currentSteps, store, wf, action, transientVars, inputs, ps))
{
checkImplicitFinish(id);
}
dosubmit();
} catch (WorkflowException e) {
context.setRollbackOnly(); // 這里調(diào)用WorkContext對(duì)象的setRollbackOnly()方法,執(zhí)行事務(wù)的回滾
throw e;
}
可以看到方法2比較"爛",看來(lái)下一步即使編寫(xiě)方法1的實(shí)現(xiàn)
posted @ 2006-03-02 21:02 killvin| 編輯 收藏
早上的時(shí)間被該死的WorkflwoStore里的主鍵生成策略("主鍵生成策略"來(lái)源于Hibernate文檔),該死的Sequence,從文檔資料上看到DB2是支持Sequence的,按照db2的文檔我執(zhí)行了如下的語(yǔ)句:
create sequence seq_os_wfentry start with 10 increment by 10;
create sequence seq_os_currentsteps;
執(zhí)行-ok
可是我以前不太了解Sequence的概念,這片資料倒是很有價(jià)值
http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0407zhang/
不過(guò)我以為查詢Sequence就只需要執(zhí)行SELECT NEXT VALUE FOR seq_os_wfentry 就ok了,可是誰(shuí)知道總是報(bào)錯(cuò)?!在比較仔細(xì)的看了這片文章之后發(fā)現(xiàn),其實(shí)根本就無(wú)法執(zhí)行這條SQL!而需要這樣
INSERT INTO EMPLOYEE ( SERIALNUMBER, FIRSTNAME, LASTNAME,
SALARY) VALUES(NEXTVAL FOR EMPSERIAL, 'Martin', 'Wong', 1000.00)
可是看看JDBCWorkflowStore的實(shí)現(xiàn),這里是JDBCWorkflowStore的主鍵生成策略!
protected long getNextEntrySequence(Connection c) throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Executing SQL statement: " + entrySequence);
}
PreparedStatement stmt = null;
ResultSet rset = null;
try {
stmt = c.prepareStatement(entrySequence);
rset = stmt.executeQuery();
rset.next();
long id = rset.getLong(1);
return id;
} finally {
cleanup(null, stmt, rset);
}
}
c.prepareStatement(entrySequence) - 其實(shí)執(zhí)行了一條SQL語(yǔ)句,所以看來(lái)JDBCWorkflow根本不支持Sequence生成策略!!
該死的實(shí)現(xiàn)方式,看來(lái)我要重載其實(shí)現(xiàn)方式,不過(guò)說(shuō)真的JDBCWorkflow的編碼人員其實(shí)水平不匝地!
posted @ 2006-03-02 21:01 killvin| 編輯 收藏
posted @ 2006-03-02 21:00 killvin| 編輯 收藏
J2EE,一方面有著一套相當(dāng)龐大的標(biāo)準(zhǔn)體系和數(shù)個(gè)不同版本,另一方面,由于市場(chǎng)上應(yīng)用服務(wù)器品種多樣,各家開(kāi)發(fā)商使用的術(shù)語(yǔ)又不盡相同,因此,圍繞著J2EE,常常有不少被人誤解的地方。本文將深入探討J2EE究竟是什么,它到底能做什么。
什么是J2EE?
在試圖給J2EE 下一個(gè)明確的定義之前,我們首先要了解J2EE 并不簡(jiǎn)單地只是一門(mén)語(yǔ)言、一種工具或一套服務(wù)。
· J2EE——Java 2 平臺(tái)企業(yè)版
簡(jiǎn)單地說(shuō),J2EE是一個(gè)標(biāo)準(zhǔn)中間件體系結(jié)構(gòu),旨在簡(jiǎn)化和規(guī)范多層分布式企業(yè)應(yīng)用系統(tǒng)的開(kāi)發(fā)和部署。J2EE方案的實(shí)施可顯著地提高系統(tǒng)的可移植性、安全性、可伸縮性、負(fù)載平衡和可重用性。
J2EE技術(shù)出現(xiàn)之前,幾家主要的中間件開(kāi)發(fā)商的產(chǎn)品各自為陣,彼此之間缺乏兼容性,可移植性差,難以實(shí)現(xiàn)互操作,沒(méi)有一個(gè)被普遍認(rèn)可的行業(yè)標(biāo)準(zhǔn)。J2EE的出現(xiàn)標(biāo)志著中間件技術(shù)在經(jīng)歷了多年的不斷摸索和經(jīng)驗(yàn)總結(jié)后,正逐步走向成熟。
J2EE的核心是一組規(guī)范和指南,定義了一個(gè)使用Java語(yǔ)言開(kāi)發(fā)多層分布式企業(yè)應(yīng)用系統(tǒng)的標(biāo)準(zhǔn)平臺(tái)。開(kāi)發(fā)人員在這些規(guī)范和指南的基礎(chǔ)上開(kāi)發(fā)企業(yè)級(jí)應(yīng)用,同時(shí)由J2EE供應(yīng)商確保不同的J2EE平臺(tái)之間的兼容性。由于基于規(guī)范的各J2EE平臺(tái)之間具有良好的兼容性, 因此J2EE應(yīng)用系統(tǒng)可以部署在不同的應(yīng)用服務(wù)器上,無(wú)需或只需進(jìn)行少量的代碼修改。
· J2EE視點(diǎn)
下面我們將從幾個(gè)不同的側(cè)面來(lái)考察J2EE,以期讀者能對(duì)J2EE有個(gè)更全面清晰的印象。
(1)J2EE:多層、分布式中間件語(yǔ)法
采用多層分布式應(yīng)用模型,J2EE將應(yīng)用開(kāi)發(fā)劃分為多個(gè)不同的層,并在每一個(gè)層上定義組件。各個(gè)應(yīng)用組件根據(jù)他們所在的層分布在同一個(gè)或不同的服務(wù)器上,共同組成基于組件的多層分布式系統(tǒng)。典型的J2EE四層結(jié)構(gòu)包括客戶層、表示邏輯層(Web層)、商業(yè)邏輯層和企業(yè)信息系統(tǒng)層。
有了J2EE,分布式系統(tǒng)的開(kāi)發(fā)變得簡(jiǎn)單了,部署的速度也可以加快。J2EE組件的分布與服務(wù)器環(huán)境無(wú)關(guān),所有的資源都可通過(guò)分布式目錄進(jìn)行訪問(wèn)。這意味著開(kāi)發(fā)人員不再需要為組件和資源的分布問(wèn)題耗費(fèi)精力,從而可以有更多的時(shí)間專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),提高開(kāi)發(fā)效率。
(2)J2EE:企業(yè)級(jí)應(yīng)用系統(tǒng)開(kāi)發(fā)平臺(tái)
J2EE本身是一個(gè)標(biāo)準(zhǔn),一個(gè)為企業(yè)分布式應(yīng)用的開(kāi)發(fā)提供的標(biāo)準(zhǔn)平臺(tái)。而J2EE的實(shí)施,則具體表現(xiàn)為諸如BEA Web logic或IBM Web sphere之類的特定Web服務(wù)器產(chǎn)品。利用J2EE應(yīng)用-編程模型開(kāi)發(fā)的企業(yè)應(yīng)用系統(tǒng),可以部署在不同廠商生產(chǎn)的、但相互兼容的J2EE 應(yīng)用服務(wù)器上。
目前,市場(chǎng)上基于J2EE的Web服務(wù)器品種繁多,性能特點(diǎn)各有千秋,每家廠商的產(chǎn)品都有精心設(shè)計(jì)的獨(dú)到之處。但與產(chǎn)品個(gè)性無(wú)關(guān)的是,所有的J2EE應(yīng)用服務(wù)器都為企業(yè)級(jí)應(yīng)用系統(tǒng)的開(kāi)發(fā)和部署提供了一個(gè)共同的基礎(chǔ)。
(3)J2EE:電子化應(yīng)用開(kāi)發(fā)模型
J2EE應(yīng)用很容易發(fā)布到Web、掌上電腦或移動(dòng)電話等手持設(shè)備上。換言之,應(yīng)用組件可以很輕松地實(shí)現(xiàn)電子化。J2EE的應(yīng)用-編程模型保證組件在向不同類型的客戶端移植過(guò)程中,商業(yè)邏輯和后端系統(tǒng)保持不變。
此外,J2EE平臺(tái)的其他主要優(yōu)點(diǎn)還有:自動(dòng)負(fù)載平衡、可伸縮、容錯(cuò)和具有故障排除等功能。部署在J2EE環(huán)境中的組件將自動(dòng)獲得上述特性,而不必增加額外的代碼開(kāi)銷(xiāo)。
J2EE所有這些特性對(duì)于需要構(gòu)建全天候網(wǎng)絡(luò)門(mén)戶的企業(yè)來(lái)說(shuō)顯得尤為重要。
(4)J2EE:Web應(yīng)用服務(wù)器上廣泛采用的標(biāo)準(zhǔn)
可以說(shuō),J2EE是首個(gè)獲得業(yè)界廣泛認(rèn)可和采納的中間件標(biāo)準(zhǔn)。目前幾乎所有的一流Web應(yīng)用服務(wù)器,如BEA的Web logic、IBM的Web sphere、HP的應(yīng)用服務(wù)器、Sun的iPlanet和Macromedia的Jrun等,都是基于J2EE的。迄今為止,還沒(méi)有哪個(gè)其他標(biāo)準(zhǔn)能獲得如此眾多的中間件供應(yīng)商的一致支持。
而且,有了J2EE,企業(yè)的應(yīng)用開(kāi)發(fā)對(duì)于某個(gè)特定的開(kāi)發(fā)商或應(yīng)用服務(wù)供應(yīng)商的依賴性更小。應(yīng)用組件只要符合J2EE規(guī)范,完全可以部署在不同的應(yīng)用服務(wù)器上。為了確保不同廠商的J2EE應(yīng)用服務(wù)器的兼容性和一致性,Sun公司發(fā)布了J2EE兼容性測(cè)試包。
· J2EE究竟是什么
至此,我們可以試著用一句話來(lái)概括J2EE,那就是:J2EE是一個(gè)中間件基礎(chǔ)架構(gòu),有了它,開(kāi)發(fā)者只需要集中精力編寫(xiě)代碼來(lái)表達(dá)企業(yè)應(yīng)用的商業(yè)邏輯和表示邏輯,至于其他系統(tǒng)問(wèn)題,如內(nèi)存管理,多線程,資源分布和垃圾收集等,都將由J2EE自動(dòng)完成。
J2EE如何應(yīng)對(duì)挑戰(zhàn)?
在這一部分里,我們將探討J2EE是如何應(yīng)對(duì)企業(yè)開(kāi)發(fā)過(guò)程中所面臨的問(wèn)題,以及如何為企業(yè)未來(lái)發(fā)展之需要提供空間。
· 獨(dú)立于硬件配置和操作系統(tǒng)
J2EE運(yùn)行在Java虛擬機(jī)(JVM)上,利用Java本身的跨平臺(tái)特性,獨(dú)立于硬件配置和操作系統(tǒng)。Java運(yùn)行環(huán)境(JRE)——JVM的可安裝版本加上其他一些重要組件——幾乎可以運(yùn)行于所有的硬件/OS組合。因此,通過(guò)采用Java,J2EE使企業(yè)免于高昂的硬件設(shè)備和操作系統(tǒng)的再投資,保護(hù)已有的IT資源。在很多情況下,J2EE還可以直接運(yùn)行在EIS服務(wù)器環(huán)境中,從而節(jié)約網(wǎng)絡(luò)帶寬,提高性能。
· 堅(jiān)持面向?qū)ο蟮脑O(shè)計(jì)原則
作為一門(mén)完全面向?qū)ο蟮恼Z(yǔ)言,Java幾乎支持所有的面向?qū)ο蟮某绦蛟O(shè)計(jì)特征。面向?qū)ο蠛突诮M件的設(shè)計(jì)原則構(gòu)成了J2EE應(yīng)用編程模型的基礎(chǔ)。
J2EE多層結(jié)構(gòu)的每一層都有多種組件模型。因此,開(kāi)發(fā)人員所要做的就是為應(yīng)用項(xiàng)目選擇適當(dāng)?shù)慕M件模型組合,靈活地開(kāi)發(fā)和裝配組件,這樣不僅有助于提高應(yīng)用系統(tǒng)的可擴(kuò)展性,還能有效地提高開(kāi)發(fā)速度,縮短開(kāi)發(fā)周期。此外,基于J2EE的應(yīng)用還具有結(jié)構(gòu)良好,模塊化,靈活和高度可重用性等優(yōu)點(diǎn)。
· 靈活性、可移植性和互操作性
利用Java的跨平臺(tái)特性,J2EE組件可以很方便地移植到不同的應(yīng)用服務(wù)器環(huán)境中。這意味著企業(yè)不必再拘泥于單一的開(kāi)發(fā)平臺(tái)。
J2EE的應(yīng)用系統(tǒng)可以部署在不同的應(yīng)用服務(wù)器上,在全異構(gòu)環(huán)境下,J2EE組件仍可彼此協(xié)同工作。這一特征使得裝配應(yīng)用組件首次獲得空前的互操作性。例如,安裝在IBM Websphere環(huán)境下的EJB,一方面可以直接與Websphere環(huán)境下的CICS直接交互,另一方面也可以通過(guò)安裝在別處的BEA Weblogic 服務(wù)器上的EJB進(jìn)行訪問(wèn)。
· 輕松的企業(yè)信息系統(tǒng)集成
J2EE技術(shù)出臺(tái)后不久,很快就將JDBC、 JMS和 JCA等一批標(biāo)準(zhǔn)納歸自身體系之下,這大大簡(jiǎn)化了企業(yè)信息系統(tǒng)整合的工作量,方便企業(yè)將諸如legacy system(早期投資系統(tǒng)),ERP和數(shù)據(jù)庫(kù)等多個(gè)不同的信息系統(tǒng)進(jìn)行無(wú)縫集成。
由于幾乎所有的關(guān)系型數(shù)據(jù)庫(kù)系統(tǒng)都支持JDBC,因此只需借助必要的JDBC驅(qū)動(dòng)程序,J2EE應(yīng)用就可以和所有主流數(shù)據(jù)庫(kù)系統(tǒng)進(jìn)行通信。類似的,目前業(yè)界正冒出一批基于Java連接器體系標(biāo)準(zhǔn)的EI適配器,也用于提供各類legacy system和ERP/CRM的無(wú)縫集成。
· 引進(jìn)面向服務(wù)的體系結(jié)構(gòu)
隨著Web服務(wù)以及SOAP等開(kāi)放標(biāo)準(zhǔn)的出現(xiàn),企業(yè)異構(gòu)系統(tǒng)之間的互操作性成為可能。J2EE,作為一個(gè)可擴(kuò)展平臺(tái),很自然需要加入Web服務(wù)特性。為此,Sun公司發(fā)布了一整套稱為“JAX包”的API,支持從XML語(yǔ)法分析、XML綁定、SOAP消息發(fā)送、注冊(cè)表查尋、XML RPC到XML消息傳遞等所有各種Web服務(wù)需求。
雖然J2EE平臺(tái)的出現(xiàn)早于Web服務(wù)技術(shù),但它的可擴(kuò)展能力使它能很好地適應(yīng)技術(shù)的最新發(fā)展。我們有理由相信,在未來(lái),J2EE將引入更多的技術(shù)進(jìn)步而不會(huì)動(dòng)搖它的核心框架和應(yīng)用-編程模型。
結(jié)束語(yǔ)
作為一個(gè)被業(yè)界廣泛采用的中間件標(biāo)準(zhǔn),J2EE是開(kāi)發(fā)可伸縮的、具有負(fù)載平衡能力的多層分布式跨平臺(tái)企業(yè)應(yīng)用的理想平臺(tái)。J2EE的首要任務(wù)在于提供一個(gè)標(biāo)準(zhǔn)中間件基礎(chǔ)架構(gòu),由該基礎(chǔ)架構(gòu)負(fù)責(zé)處理企業(yè)開(kāi)發(fā)中所涉及的所有系統(tǒng)級(jí)問(wèn)題,從而使得開(kāi)發(fā)人員可以集中精力重視商業(yè)邏輯的設(shè)計(jì)和應(yīng)用的表示,提高開(kāi)發(fā)工作的效率。
J2EE有效地滿足了行業(yè)需求,提供獨(dú)立于操作系統(tǒng)的開(kāi)發(fā)環(huán)境。基于J2EE的應(yīng)用系統(tǒng)靈活且易于移植和重用,可運(yùn)行在不同廠家的Web服務(wù)器上。更為重要的是,J2EE是一個(gè)開(kāi)放體系,完全有能力適應(yīng)未來(lái)技術(shù)的進(jìn)步和發(fā)展。
posted @ 2006-03-02 20:59 killvin| 編輯 收藏
該文轉(zhuǎn)自guty
O-R Mapping
J2EE的標(biāo)準(zhǔn)是CMP Entity Bean,而實(shí)際應(yīng)用中受到詬病最多的也是它。我們化了整整半年時(shí)間研究CMP2.0的開(kāi)發(fā)方法,目前總算能夠?qū)⒋a量減少到70%,并且有希望減少到 90%。我曾經(jīng)很滿足現(xiàn)有的成績(jī),但是當(dāng)我真正地閱讀了hibernate后,對(duì)CMP2.0的信心徹底動(dòng)搖了。
hibernate至少比CMP2.0有以下優(yōu)點(diǎn):
1. 兼容性。 規(guī)范一模一樣,實(shí)現(xiàn)各有不同,這是CMP的現(xiàn)狀。用第三方O-R Mapping工具可以解決這個(gè)問(wèn)題。
2. 保護(hù)智力投資。在了解了Orion, Weblogic, JBoss的CMP實(shí)現(xiàn)后,我不愿意再去學(xué)習(xí)Websphere 或者Resin的實(shí)現(xiàn)了。
3. 性能。
a. local v.s. remote, hibernate、JDO、Castor都是本地調(diào)用,CMP2.0雖然也有Local接口,但是Web層還是需要通過(guò)Remote接口訪問(wèn)EJB層的數(shù)據(jù),序列化、網(wǎng)絡(luò)調(diào)用、創(chuàng)建大量的對(duì)象,都是性能降低的原因。
b. transaction,J2EE提出了一個(gè)全新的事務(wù)模型(method-based descriptor),對(duì)程序員的開(kāi)發(fā)確實(shí)是個(gè)“簡(jiǎn)化”,記得一本教程建議所有的EJB方法都用Required。但這樣的結(jié)果是什么?性能極度降低!互鎖!沒(méi)有辦法,我們只有再去調(diào)節(jié)各個(gè)方法的Transaction屬性,然后又出現(xiàn) 新的互鎖...
新的事務(wù)模型是不成功的。它試圖簡(jiǎn)化問(wèn)題,卻引入了更為嚴(yán)重的問(wèn)題。各家廠商的Transaction實(shí)現(xiàn)也不盡相同,有的支持Optimistic Lock,有的在VM中同步Entity對(duì)象,又是兼容性的一大敵。
hibernate沒(méi)有試圖創(chuàng)造一個(gè)更新的模式,相反,它沿用了傳統(tǒng)數(shù)據(jù)庫(kù)的Transaction編程模式,在對(duì)J2EE的Transaction傷透腦筋后看到它,真是十分親切,感覺(jué)自己確實(shí)在編程,而不是碰運(yùn)氣填代碼了。
4. 動(dòng)態(tài)Query。
Entity Bean很難實(shí)現(xiàn)動(dòng)態(tài)Query,這是因?yàn)樗诖a自動(dòng)生成技術(shù),即最終的執(zhí)行代碼是在部署編譯時(shí)生成的。hibernate則有根本的改變,它基于 reflection機(jī)制,運(yùn)行時(shí)動(dòng)態(tài)Query是很自然的事。另外,hibernate幾乎支持所有的SQL語(yǔ)法,傳統(tǒng)數(shù)據(jù)庫(kù)可以做的它就可以做。
5. 發(fā)展速度。
I have a dream, 有一天Entity Bean會(huì)變得很好。但至少目前來(lái)看,Entity Bean是一個(gè)不完善的產(chǎn)品,它是大公司政治斗爭(zhēng)和妥協(xié)的產(chǎn)品,而且習(xí)慣性將一些問(wèn)題“無(wú)限期擱置”,典型的例子就是Query(之所以不提其他問(wèn)題,是因?yàn)槠渌际荅ntity Bean的致命傷:))
形成強(qiáng)烈反差的是,hibernate的核心程序員只有一人,但它改進(jìn)的速度確是Entity Bean無(wú)法企及的。
6. 繼承和多態(tài)。
OO語(yǔ)言的精華在Entity Bean這里是行不通的,我曾經(jīng)自我安慰將Entity Bean看做一個(gè)“內(nèi)存中的數(shù)據(jù)表”,才找到了一點(diǎn)平衡。
但當(dāng)我看到hibernate時(shí),又開(kāi)始不平衡了。
另外,CMP2.0也有一些缺點(diǎn)是可以彌補(bǔ)的。
1. 代碼維護(hù)。
大量的接口文件和配置文件,開(kāi)發(fā)和維護(hù)的工作量很大。
解決途徑:采用xdoclet,可以自動(dòng)產(chǎn)生眾多的接口和配置文件,甚至facade, delegate等高級(jí)模式。
至少目前來(lái)看,hibernate的缺點(diǎn)有:
1. 代碼維護(hù)
hibernate提供了自動(dòng)生成mapping文件“框架”的工具,但還需要手工調(diào)節(jié)。而這類開(kāi)發(fā),能想到的最佳模式就是xdoclet的(代碼+注釋)的模式了。幸好,hibernate的程序員已經(jīng)向xdoclet項(xiàng)目增加了hibernate的模塊。現(xiàn)在需要的是等待xdoclet的下一個(gè) release。
結(jié)論:
hibernate至少?gòu)奈臋n上超越了Entity Bean很多,我要學(xué)習(xí)hibernate。
以下是robbin的觀點(diǎn)
如果說(shuō)不使用Session Facade模式的話,我認(rèn)為EB還是一個(gè)很有意義的的東西,因?yàn)镋B是唯一直接支持跨RMI的持久化方案。但是由于EB的效率和減少跨RMI的網(wǎng)絡(luò)調(diào)用的原因,EB已經(jīng)完全被封裝到SB的后面,EB的分布式調(diào)用的功能,EB的安全驗(yàn)證功能,EB的容器事務(wù)功能完全被前面的SB給做了,結(jié)果EB就只剩下了唯一的ORM功能了,單就ORM這一點(diǎn)來(lái)說(shuō)EB實(shí)在是一個(gè)非常非常糟糕的東西。那么EB還有什么功能值得我非去用它不可呢?
用 Session Bean + DAO + Hibernate 來(lái)取代 Session Bean + Entity Bean,不但能夠極大降低軟件設(shè)計(jì)難度,軟件開(kāi)發(fā)難度,軟件調(diào)試難度和軟件部署難度,而且還可以提高允許效率,降低硬件要求。
不要把EB直接拿來(lái)和Hibernate做比較,兩者不是一個(gè)范疇的東西,而應(yīng)該整體比較兩種方案:
Session Bean + DAO + Hibernate
Session Bean + Entity Bean
我找不出來(lái)第二方案有哪怕一點(diǎn)方面能夠比第一方案好的。
CMP可以使用CMR來(lái)表示多表之間通過(guò)外鍵關(guān)聯(lián)的關(guān)系。但是你仍然會(huì)遇到即使沒(méi)有鍵關(guān)聯(lián)的表仍然需要連接查詢的情況,這是一個(gè)非常普遍的現(xiàn)象。
如果是Hibernate,可以在HSQL里面定義outer join,BMP也可以寫(xiě)JDBC,而CMP沒(méi)有任何辦法來(lái)解決該問(wèn)題,除非你把需要的連接查詢都定義為CMR,但那樣的話,凡是有需要連接查詢,或者有鍵關(guān)聯(lián)的表都必須打在一個(gè)包里面。你如果不打在一個(gè)jar包里面,如果能夠建立CMR?不是我想放在一個(gè)jar里面,而是不得不放在一個(gè)jar里面。基本上CMP還是非常笨拙的。
CMP的另一大缺點(diǎn)是不能動(dòng)態(tài)SQL,guty已經(jīng)提到了,一個(gè)SQL就要定義一個(gè)EJBFinder方法,在編譯的時(shí)候就確定死了。在實(shí)際應(yīng)用中,經(jīng)常會(huì)遇到不確定查詢條件的查詢,比如說(shuō)用戶在頁(yè)面上用下拉列表來(lái)選擇查詢的條件,用戶既有可能什么限制條件都不選,也有可能選擇某幾個(gè)條件。這時(shí)候你怎么辦?假設(shè)有n個(gè)查詢條件,你要寫(xiě) C1n + C2n + C3n +...+ Cnn(C是組合公式的符合,n是下標(biāo),1...n是上標(biāo))個(gè)EJBFinder方法才行,很恐怖吧。
其實(shí)JDBC的PrepareStatement也不能很好的解決這個(gè)問(wèn)題,因?yàn)樗前凑?,2這樣的次序來(lái)set參數(shù)的。用Statement是肯定不行的,會(huì)嚴(yán)重影響數(shù)據(jù)庫(kù),甚至?xí)?dǎo)致數(shù)據(jù)庫(kù)down掉(我的實(shí)際經(jīng)驗(yàn))。但是Hibernate就解決的不錯(cuò),因?yàn)樗梢园凑?:name 這樣的形式來(lái)設(shè)定SQL中的Placeholder,這樣set參數(shù)就可以按照參數(shù)名稱傳遞,因?yàn)榇涡虿皇撬赖模诔绦蚶锩婢秃苋菀赘鶕?jù)用戶選擇的查詢條件,動(dòng)態(tài)的產(chǎn)生SQL,動(dòng)態(tài)的set參數(shù)了。
CMP2.0還有一個(gè)大問(wèn)題是不支持order by,當(dāng)然你可以在Java里面對(duì)取出來(lái)的集合排序,但是速度和數(shù)據(jù)庫(kù)里面就排好序速度不在一個(gè)數(shù)量級(jí)了。Hibernate不但可以order by,還可以group by,having,子查詢,真是沒(méi)有辦法比下去了。
其實(shí)對(duì)于動(dòng)態(tài)SQL和排序問(wèn)題,特定的App Server也可以做,但那不是CMP2.0的規(guī)范罷了,所以為了可移植性,也不敢隨便去用。
在項(xiàng)目開(kāi)發(fā)時(shí), 開(kāi)發(fā)和運(yùn)行效率以及靈活性是非常重要的指標(biāo)。由于Entity Bean天生是一種粗粒度的使用方式,這就必定使它在裝載的時(shí)候有較長(zhǎng)的響應(yīng)時(shí)間,也不能自如的支持懶裝入的方式,使用成細(xì)粒度會(huì)使程序變得復(fù)雜,以及遠(yuǎn)程調(diào)用細(xì)粒度的entity bean是一種非??膳碌男袨? 太慢了.
Hibernate正好滿足開(kāi)發(fā)和運(yùn)行效率以及靈活性,說(shuō)來(lái)說(shuō)去,它可以稱做一個(gè)OO化的JDBC, 這樣大家就不會(huì)對(duì)Hibernate產(chǎn)生誤解及恐懼心理。它支持粗細(xì)兩種粒度方式,運(yùn)用起來(lái)靈活自如,前提是你必知道如何使用,一個(gè)entity bean 實(shí)現(xiàn)要N種重復(fù)的方法, such as ejbRemove,ejbstore,ejb...., 光類也有一大堆,象Home Interface, Romote Interface..., Primary class if necessary. Hibernate只需要一個(gè)就行了。
CMP在進(jìn)行O/R Mapping方面只是做了最基礎(chǔ)的工作而已,完全用CMP做數(shù)據(jù)層,會(huì)發(fā)現(xiàn)你在把數(shù)據(jù)庫(kù)應(yīng)該做的工作全部都搬到App Server里面來(lái)重新實(shí)現(xiàn)一遍,有這必要嗎?
CMP是把EJBQL寫(xiě)死在ejb-jar.xml里面的,所以n個(gè)條件就需要(c0n+c1n+...cnn )2的n次方個(gè)EJBFinder方法,簡(jiǎn)直沒(méi)有辦法說(shuō)。
JDBC實(shí)現(xiàn)PrepareStatement的動(dòng)態(tài)SQL構(gòu)造不是不能夠,而是非常麻煩,需要寫(xiě)一個(gè)非常非常大的if elseif else嵌套的判斷。
Hibernate實(shí)現(xiàn)起來(lái)特別簡(jiǎn)單,(其實(shí)OJB也實(shí)現(xiàn)了PrepareStatement的動(dòng)態(tài)SQL構(gòu)造)這本身并不復(fù)雜,但是需要你多寫(xiě)些代碼而已,由于CMP把EJBQL寫(xiě)死在配置文件里面了,你連選擇的余地都沒(méi)有。
posted @ 2006-03-02 20:58 killvin| 編輯 收藏
A reader asked a question via a comment a couple months ago that I didn't really have an answer for (and had always kind of wondered the same thing). In the original post (which showed how to use JDBC with ColdFusion), I used the following snippet of code:
Class.forName("jdbc.DriverXYZ");
Connection con = DriverManager.getConnection(url,
"myLogin", "myPassword");
and the reader wanted to know what the Class.forName(..)
method did. The most common answer you'll hear is that it loads the database driver, which, while technically true, is shallow. Where does it get loaded? How does it happen? And why?
To answer the question I started with the JavaDoc for the Class.forName() method. According to the documentation, the method:
... attempts to locate, load, and link the class or interfaceI wasn't perfectly clear on what "locate, load, and link" meant, so I did a little digging through the Java Language Specification. According to chapter 12 of the JLS:
Loading refers to the process of finding the binary form of a class or interface type with a particular name, perhaps by computing it on the fly, but more typically by retrieving a binary representation previously computed from source code by a compiler, and constructing, from that binary form, a Class object to represent the class or interface.Next, again according to the JLS, it must be transformed from it's binary representation to something the Java virtual machine can use, this process is called linking. Finally, the class is initialized, which is the process that executes the static initializer and the initializers for static fields declared in the class.
So then back to the original problem, when Class.forName() is called with an argument like this:
Class.forName("org.gjt.mm.mysql.Driver");
the classloader attempts to load and link the Driver
class in the "org.gjt.mm.mysql" package and if successful, the static initializer is run. The MySQL Driver
(download the source code) static initializer looks like this:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
So it calls a static method in the java.sql.DriverManager class which apparently registers a copy of itself when it loads.
So now I understand the where and the how, what about why? To understand the why you have to look at the next line in the initial code example:
Connection con = DriverManager.getConnection(url,
"myLogin", "myPassword");
The DriverManager
class (view DriverManager source here) returns a database connection given a JDBC URL string, a username and a password. In order to create that connection, the DriverManager class has to know which database driver you want to use. It does that by iterating over the array (internally a Vector) of drivers that have registered with it (ie: the registerDriver(Driver driver)
method illustrated above) and calls the acceptsURL(url))
method on each driver in the array, effectively asking the driver to tell it whether or not it can handle the JDBC URL.
So there you have it. Class.forName explained.
posted @ 2006-03-02 20:57 killvin| 編輯 收藏
原文: http://forum.javaeye.com/viewtopic.php?t=17912
摟主的問(wèn)題問(wèn)的含含糊糊:flyjie給出了非常詳細(xì)的解釋,
不過(guò)就是沒(méi)有解釋String實(shí)例化的特殊方面以及Intern()方法的含義
-------
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
java代碼:
String str ;
這樣聲明str它只支是一個(gè)對(duì)象的reference,不會(huì)產(chǎn)生實(shí)際的對(duì)象。如果沒(méi)有初始化str,編譯時(shí)便會(huì)發(fā)生錯(cuò)誤。
java代碼:
String str1=new String("test");
String str2 = "test";
str1是一個(gè)新的對(duì)象。new關(guān)鍵字的意思就是創(chuàng)建某個(gè)新的對(duì)象。而str2是一個(gè)對(duì)象的引用。 它們的內(nèi)容相同,但內(nèi)存地址是不一樣的。 java中對(duì)象的引用存在Stack(棧)中,而對(duì)象由Heap(堆)分配空間。
3、引用==變量? 不一定
java代碼:
public class TestString {
public static void main(String[] args) {
String s1 = "test";
String s2 = new String("test");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else System.out.println("s1 not equals s2");
}
}
我們將 s2 用 new 操作符創(chuàng)建程序輸出:s1 != s2 s1 equals s2.
java代碼:
s2 = s2.intern();
在你加上這句話后,上面的程序輸入:s1 == s2 s1 equals s2
而String a = "test" ; String b = "test" ; a == b 會(huì)返回true; 這里a="test"時(shí)創(chuàng)建一個(gè)在棧中的reference, b=test時(shí)jvm發(fā)現(xiàn)棧中已存在名為"test"的字符串,直接引用。結(jié)論:String 是個(gè)對(duì)象,要對(duì)比兩個(gè)不同的String對(duì)象的值是否相同明顯的要用到 equals() 這個(gè)方法. 而== 比較的是內(nèi)存地址的值。
4、private final String a = "test", 這個(gè)a屬于常量,存放在常量存儲(chǔ)空間(CS)中。
5、建議你看看<<深入淺出java虛擬機(jī)>>一書(shū)。
-------
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
總結(jié)
1. 在學(xué)習(xí)JAVA的時(shí)候就知道==比較的是內(nèi)存地址.而equals比較的是內(nèi)存地址對(duì)應(yīng)的值?。墒沁€是有很多的人問(wèn)來(lái)問(wèn)去的,真不知道他們JAVA的基礎(chǔ)課程是怎么學(xué)的??。?BR>
2. JAVA所有的對(duì)象都是存放在堆中的!你獲取的"對(duì)象"僅僅只是對(duì)象的引用而已
3. String是比較特殊的對(duì)象,特殊在
3.1 > String a = new String("test") -此時(shí)你是在堆中實(shí)例化了一個(gè)字符串對(duì)象
3.2 > String b = "test"-此時(shí)JVM會(huì)先去堆中尋找這樣的對(duì)象;如果有就返回此對(duì)象的引用;如果沒(méi)有就重新實(shí)例化一個(gè)這樣的對(duì)象!基于這樣的一個(gè)過(guò)程所以JAVA要求String不可以更改值的。
3.3 >intern()方法就是試圖完成這樣的一個(gè)尋找過(guò)程
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
這里有一份詳細(xì)的參考資料:
關(guān)于Java棧與堆的思考 http://www.javafan.net/article/20051123115654293.html
posted @ 2006-03-02 20:56 killvin| 編輯 收藏
網(wǎng)上的一些關(guān)于內(nèi)部類的概念是不完整的,還是看看SUN的文檔上的標(biāo)準(zhǔn)答案。
...
Like other members, a nested class can be declared static (or not). A static nested class is called just that: a static nested class. A nonstatic nested class is called an inner class.
- Nested class分為靜態(tài)Static nested class 的和非靜態(tài)的 inner class, 在SUN的眼里只有Nested Class?。?BR>
As with static methods and variables, which we call class methods and variables, a static nested class is associated with its enclosing class. And like class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class — it can use them only through an object reference.
- 靜態(tài)的Static nested class是不可以直接調(diào)用它的外部類enclosing class的,但是可以通過(guò)外部類的引用來(lái)調(diào)用,就像你在一個(gè)類中寫(xiě)了main方法一樣。
...
As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's instance variables and methods. Also, because an inner class is associated with an instance, it cannot define any static members itself.
-非靜態(tài)類inner class 可以自由的引用外部類的屬性和方法,但是它與一個(gè)實(shí)例綁定在了以其,不可以定義靜態(tài)的屬性、方法(這點(diǎn)不是很理解,可能需要看JVM的類實(shí)現(xiàn))
...
class EnclosingClass {
...
class InnerClass {
...
}
}
The interesting feature about the relationship between these two classes is not that InnerClass is syntactically defined within EnclosingClass. Rather, it's that an instance of InnerClass can exist only within an instance of EnclosingClass and that it has direct access to the instance variables and methods of its enclosing instance. The next figure illustrates this idea.

-圖形化的嵌入類與外部類的關(guān)系
posted @ 2006-03-02 20:55 killvin| 編輯 收藏
提起Java內(nèi)部類(Inner Class)可能很多人不太熟悉,實(shí)際上類似的概念在C++里也有,那就是嵌套類(Nested Class),關(guān)于這兩者的區(qū)別與聯(lián)系,在下文中會(huì)有對(duì)比。內(nèi)部類從表面上看,就是在類中又定義了一個(gè)類(下文會(huì)看到,內(nèi)部類可以在很多地方定義),而實(shí)際上并沒(méi)有那么簡(jiǎn)單,乍看上去內(nèi)部類似乎有些多余,它的用處對(duì)于初學(xué)者來(lái)說(shuō)可能并不是那么顯著,但是隨著對(duì)它的深入了解,你會(huì)發(fā)現(xiàn)Java的設(shè)計(jì)者在內(nèi)部類身上的確是用心良苦。學(xué)會(huì)使用內(nèi)部類,是掌握J(rèn)ava高級(jí)編程的一部分,它可以讓你更優(yōu)雅地設(shè)計(jì)你的程序結(jié)構(gòu)。下面從以下幾個(gè)方面來(lái)介紹:
·第一次見(jiàn)面
public interface Contents {
int value();
}
public interface Destination {
String readLabel();
}
public class Goods {
private class Content implements Contents {
private int i = 11;
public int value() {
return i;
}
}
protected class GDestination implements Destination {
private String label;
private GDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
}
public Destination dest(String s) {
return new GDestination(s);
}
public Contents cont() {
return new Content();
}
}
class TestGoods {
public static void main(String[] args) {
Goods p = new Goods();
Contents c = p.cont();
Destination d = p.dest("Beijing");
}
}
在這個(gè)例子里類Content和GDestination被定義在了類Goods內(nèi)部,并且分別有著protected和private修飾符來(lái)控制訪問(wèn)級(jí)別。Content代表著Goods的內(nèi)容,而GDestination代表著Goods的目的地。它們分別實(shí)現(xiàn)了兩個(gè)接口Content和Destination。在后面的main方法里,直接用 Contents c和Destination d進(jìn)行操作,你甚至連這兩個(gè)內(nèi)部類的名字都沒(méi)有看見(jiàn)!這樣,內(nèi)部類的第一個(gè)好處就體現(xiàn)出來(lái)了——隱藏你不想讓別人知道的操作,也即封裝性。
同時(shí),我們也發(fā)現(xiàn)了在外部類作用范圍之外得到內(nèi)部類對(duì)象的第一個(gè)方法,那就是利用其外部類的方法創(chuàng)建并返回。上例中的cont()和dest()方法就是這么做的。那么還有沒(méi)有別的方法呢?當(dāng)然有,其語(yǔ)法格式如下:
outerObject=new outerClass(Constructor Parameters);
outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);
注意在創(chuàng)建非靜態(tài)內(nèi)部類對(duì)象時(shí),一定要先創(chuàng)建起相應(yīng)的外部類對(duì)象。至于原因,也就引出了我們下一個(gè)話題——
·非靜態(tài)內(nèi)部類對(duì)象有著指向其外部類對(duì)象的引用
對(duì)剛才的例子稍作修改:
public class Goods {
private valueRate=2;
private class Content implements Contents {
private int i = 11*valueRate;
public int value() {
return i;
}
}
protected class GDestination implements Destination {
private String label;
private GDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
}
public Destination dest(String s) {
return new GDestination(s);
}
public Contents cont() {
return new Content();
}
}
修改的部分用藍(lán)色顯示了。在這里我們給Goods類增加了一個(gè)private成員變量valueRate,意義是貨物的價(jià)值系數(shù),在內(nèi)部類Content的方法value()計(jì)算價(jià)值時(shí)把它乘上。我們發(fā)現(xiàn),value()可以訪問(wèn)valueRate,這也是內(nèi)部類的第二個(gè)好處——一個(gè)內(nèi)部類對(duì)象可以訪問(wèn)創(chuàng)建它的外部類對(duì)象的內(nèi)容,甚至包括私有變量!這是一個(gè)非常有用的特性,為我們?cè)谠O(shè)計(jì)時(shí)提供了更多的思路和捷徑。要想實(shí)現(xiàn)這個(gè)功能,內(nèi)部類對(duì)象就必須有指向外部類對(duì)象的引用。Java編譯器在創(chuàng)建內(nèi)部類對(duì)象時(shí),隱式的把其外部類對(duì)象的引用也傳了進(jìn)去并一直保存著。這樣就使得內(nèi)部類對(duì)象始終可以訪問(wèn)其外部類對(duì)象,同時(shí)這也是為什么在外部類作用范圍之外向要?jiǎng)?chuàng)建內(nèi)部類對(duì)象必須先創(chuàng)建其外部類對(duì)象的原因。
有人會(huì)問(wèn),如果內(nèi)部類里的一個(gè)成員變量與外部類的一個(gè)成員變量同名,也即外部類的同名成員變量被屏蔽了,怎么辦?沒(méi)事,Java里用如下格式表達(dá)外部類的引用:
outerClass.this
有了它,我們就不怕這種屏蔽的情況了。
·靜態(tài)內(nèi)部類
和普通的類一樣,內(nèi)部類也可以有靜態(tài)的。不過(guò)和非靜態(tài)內(nèi)部類相比,區(qū)別就在于靜態(tài)內(nèi)部類沒(méi)有了指向外部的引用。這實(shí)際上和C++中的嵌套類很相像了,Java內(nèi)部類與C++嵌套類最大的不同就在于是否有指向外部的引用這一點(diǎn)上,當(dāng)然從設(shè)計(jì)的角度以及以它一些細(xì)節(jié)來(lái)講還有區(qū)別。
除此之外,在任何非靜態(tài)內(nèi)部類中,都不能有靜態(tài)數(shù)據(jù),靜態(tài)方法或者又一個(gè)靜態(tài)內(nèi)部類(內(nèi)部類的嵌套可以不止一層)。不過(guò)靜態(tài)內(nèi)部類中卻可以擁有這一切。這也算是兩者的第二個(gè)區(qū)別吧。
·局部?jī)?nèi)部類
是的,Java內(nèi)部類也可以是局部的,它可以定義在一個(gè)方法甚至一個(gè)代碼塊之內(nèi)。
public class Goods1 {
public Destination dest(String s) {
class GDestination implements Destination {
private String label;
private GDestination(String whereTo) {
label = whereTo;
}
public String readLabel() { return label; }
}
return new GDestination(s);
}
public static void main(String[] args) {
Goods1 g= new Goods1();
Destination d = g.dest("Beijing");
}
}
上面就是這樣一個(gè)例子。在方法dest中我們定義了一個(gè)內(nèi)部類,最后由這個(gè)方法返回這個(gè)內(nèi)部類的對(duì)象。如果我們?cè)谟靡粋€(gè)內(nèi)部類的時(shí)候僅需要?jiǎng)?chuàng)建它的一個(gè)對(duì)象并創(chuàng)給外部,就可以這樣做。當(dāng)然,定義在方法中的內(nèi)部類可以使設(shè)計(jì)多樣化,用途絕不僅僅在這一點(diǎn)。
下面有一個(gè)更怪的例子:
public class Goods2{
private void internalTracking(boolean b) {
if(b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() { return id; }
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
}
public void track() { internalTracking(true); }
public static void main(String[] args) {
Goods2 g= new Goods2();
g.track();
}
}
你不能在if之外創(chuàng)建這個(gè)內(nèi)部類的對(duì)象,因?yàn)檫@已經(jīng)超出了它的作用域。不過(guò)在編譯的時(shí)候,內(nèi)部類TrackingSlip和其他類一樣同時(shí)被編譯,只不過(guò)它由它自己的作用域,超出了這個(gè)范圍就無(wú)效,除此之外它和其他內(nèi)部類并沒(méi)有區(qū)別。
·匿名內(nèi)部類
java的匿名內(nèi)部類的語(yǔ)法規(guī)則看上去有些古怪,不過(guò)如同匿名數(shù)組一樣,當(dāng)你只需要?jiǎng)?chuàng)建一個(gè)類的對(duì)象而且用不上它的名字時(shí),使用內(nèi)部類可以使代碼看上去簡(jiǎn)潔清楚。它的語(yǔ)法規(guī)則是這樣的:
new interfacename(){......}; 或 new superclassname(){......};
下面接著前面繼續(xù)舉例子:
public class Goods3 {
public Contents cont(){
return new Contents(){
private int i = 11;
public int value() {
return i;
}
};
}
}
這里方法cont()使用匿名內(nèi)部類直接返回了一個(gè)實(shí)現(xiàn)了接口Contents的類的對(duì)象,看上去的確十分簡(jiǎn)潔。
在java的事件處理的匿名適配器中,匿名內(nèi)部類被大量的使用。例如在想關(guān)閉窗口時(shí)加上這樣一句代碼:
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
有一點(diǎn)需要注意的是,匿名內(nèi)部類由于沒(méi)有名字,所以它沒(méi)有構(gòu)造函數(shù)(但是如果這個(gè)匿名內(nèi)部類繼承了一個(gè)只含有帶參數(shù)構(gòu)造函數(shù)的父類,創(chuàng)建它的時(shí)候必須帶上這些參數(shù),并在實(shí)現(xiàn)的過(guò)程中使用super關(guān)鍵字調(diào)用相應(yīng)的內(nèi)容)。如果你想要初始化它的成員變量,有下面幾種方法:
1.如果是在一個(gè)方法的匿名內(nèi)部類,可以利用這個(gè)方法傳進(jìn)你想要的參數(shù),不過(guò)記住,這些參數(shù)必須被聲明為final。
2.將匿名內(nèi)部類改造成有名字的局部?jī)?nèi)部類,這樣它就可以擁有構(gòu)造函數(shù)了。
3.在這個(gè)匿名內(nèi)部類中使用初始化代碼塊。
·為什么需要內(nèi)部類?
java內(nèi)部類有什么好處?為什么需要內(nèi)部類?
首先舉一個(gè)簡(jiǎn)單的例子,如果你想實(shí)現(xiàn)一個(gè)接口,但是這個(gè)接口中的一個(gè)方法和你構(gòu)想的這個(gè)類中的一個(gè)方法的名稱,參數(shù)相同,你應(yīng)該怎么辦?這時(shí)候,你可以建一個(gè)內(nèi)部類實(shí)現(xiàn)這個(gè)接口。由于內(nèi)部類對(duì)外部類的所有內(nèi)容都是可訪問(wèn)的,所以這樣做可以完成所有你直接實(shí)現(xiàn)這個(gè)接口的功能。
不過(guò)你可能要質(zhì)疑,更改一下方法的不就行了嗎?
的確,以此作為設(shè)計(jì)內(nèi)部類的理由,實(shí)在沒(méi)有說(shuō)服力。
真正的原因是這樣的,java中的內(nèi)部類和接口加在一起,可以的解決常被C++程序員抱怨java中存在的一個(gè)問(wèn)題——沒(méi)有多繼承。實(shí)際上,C++的多繼承設(shè)計(jì)起來(lái)很復(fù)雜,而java通過(guò)內(nèi)部類加上接口,可以很好的實(shí)現(xiàn)多繼承的效果。
posted @ 2006-03-02 20:54 killvin| 編輯 收藏
在使用response的過(guò)程中經(jīng)常會(huì)遇到跳轉(zhuǎn)頁(yè)面的事情,這個(gè)時(shí)候有兩種情況供你選擇
1。就是調(diào)用
ServletContext.getRequestDispatcher(java.lang.String).forward(request ,
response) ;
2。就是調(diào)用response.setRedirect(),可是這兩個(gè)方法有什么不同呢?
看看TSS上關(guān)于這個(gè)問(wèn)題的解釋:
Difference request.forward() and response.sendRedirect .
Posted by: Kapil Israni on August 24, 2000 in response to Message #2253 1
replies in this thread
i suppose u r talking bout requestDispatcher.forward() here.
well basically both method calls redirect u to new resource/page/servlet.
the difference between the two is that sendRedirect always sends a header
back to the client/browser. this header then contains the
resource(page/servlet) which u wanted to be redirected. the browser uses
this header to make another fresh request. thus sendRedirect has a overhead
as to the extra remort trip being incurred. its like any other Http request
being generated by ur browser. the advantage is that u can point to any
resource(whether on the same domain or some other domain). for eg if
sendRedirect was called at www.mydomain.com then it can also be used to
redirect a call to a resource on www.theserverside.com.
where as in case of forward() call, the above is not true. resources from
the server, where the fwd. call was made, can only be requested for. but
the major diff between the two is that forward just routes the request to
the new resources which u specify in ur forward call. that means this route
is made by the servlet engine at the server level only. no headers r sent
to the browser which makes this very eficient. also the request and
response objects remain the same both from where the forward call was made
and the resource which was called.
i hope i have hit ur question right.
posted @ 2006-03-02 20:54 killvin| 編輯 收藏
Java Language Keywords
Here's a list of keywords in the Java language. These words are reserved — you cannot use any of these words as names in your programs.
true
,false
, andnull
are not keywords but they are reserved words, so you cannot use them as names in your programs either.abstract | continue | for | new | switch
assert*** | default | goto* | package | synchronized
boolean | do | if | private | this
break | double | implements | protected | throw
byte | else | import | public throws
case | enum**** | instanceof | return | transient
catch | extends | int | short | try
char | final | interface | static | void
class | finally | long | strictfp** | volatile
const* | float | native | super | while
* not used
** added in 1.2
*** added in 1.4
**** added in 5.0
Key: strictfp**
使用對(duì)象:類、方法
自Java2以來(lái),Java語(yǔ)言增加了一個(gè)關(guān)鍵字strictfp,雖然這個(gè)關(guān)鍵字在大多數(shù)場(chǎng)合比較少用,但是還是有必要了解一下。
strictfp的意思是FP-strict,也就是說(shuō)精確浮點(diǎn)的意思。在Java虛擬機(jī)進(jìn)行浮點(diǎn)運(yùn)算時(shí),如果沒(méi)有指定strictfp關(guān)鍵字時(shí),Java的編譯器以及運(yùn)行環(huán)境在對(duì)浮點(diǎn)運(yùn)算的表達(dá)式是采取一種近似于我行我素的行為來(lái)完成這些操作,以致于得到的結(jié)果往往無(wú)法令你滿意。而一旦使用了strictfp來(lái)聲明一個(gè)類、接口或者方法時(shí),那么所聲明的范圍內(nèi)Java的編譯器以及運(yùn)行環(huán)境會(huì)完全依照浮點(diǎn)規(guī)范IEEE-754來(lái)執(zhí)行。因此如果你想讓你的浮點(diǎn)運(yùn)算更加精確,而且不會(huì)因?yàn)椴煌挠布脚_(tái)所執(zhí)行的結(jié)果不一致的話,那就請(qǐng)用關(guān)鍵字strictfp。
你可以將一個(gè)類、接口以及方法聲明為strictfp,但是不允許對(duì)接口中的方法以及構(gòu)造函數(shù)聲明strictfp關(guān)鍵字,例如下面的代碼:
1. 合法的使用關(guān)鍵字strictfp
strictfp interface A {}
public strictfp class FpDemo1 {
strictfp void f() {}
}
2. 錯(cuò)誤的使用方法
interface A {
strictfp void f();
}
public class FpDemo2 {
strictfp FpDemo2() {}
}
一旦使用了關(guān)鍵字strictfp來(lái)聲明某個(gè)類、接口或者方法時(shí),那么在這個(gè)關(guān)鍵字所聲明的范圍內(nèi)所有浮點(diǎn)運(yùn)算都是精確的,符合IEEE-754規(guī)范的。例如一個(gè)類被聲明為strictfp,那么該類中所有的方法都是strictfp的。
Keys: volatile
使用對(duì)象:字段
介紹:因?yàn)楫惒骄€程可以訪問(wèn)字段,所以有些優(yōu)化操作是一定不能作用在字段上的。volatile有時(shí)
可以代替synchronized。
Keys:transient
使用對(duì)象:字段
介紹:字段不是對(duì)象持久狀態(tài)的一部分,不應(yīng)該把字段和對(duì)象一起串起。
posted @ 2006-03-02 20:53 killvin| 編輯 收藏
引言
記得當(dāng)初參與某公司的ERP項(xiàng)目中,接觸過(guò)異??蚣苓@個(gè)概念,可是似乎并沒(méi)有感覺(jué)到當(dāng)時(shí)技術(shù)經(jīng)理提出這個(gè)概念的意義,而且他也對(duì)這個(gè)概念似乎很"保守",雖然按照他的思路去執(zhí)行,但沒(méi)有理解的概念再實(shí)施起來(lái)的時(shí)候總是覺(jué)得很"別扭",而如今面對(duì)自己要設(shè)計(jì)咚咚了,不得不重新審視異常這個(gè)概念,JAVA異常的介紹文章在網(wǎng)絡(luò)上非常的少,而對(duì)于如何構(gòu)件J2EE的異常處理框架更顯的稀少,于是就促使自己寫(xiě)下了這樣的文章。
本文只是自己的一些愚見(jiàn),希望和大家相互學(xué)習(xí)。Email:Killvin@hotmail.com
概念
什么是異常?
異常(exception)應(yīng)該是異常事件(exceptional event)的縮寫(xiě)。
異常定義:異常是一個(gè)在程序執(zhí)行期間發(fā)生的事件,它中斷正在執(zhí)行的程序的正常的指令流。
當(dāng)在一個(gè)方法中發(fā)生錯(cuò)誤的時(shí)候,這個(gè)方法創(chuàng)建一個(gè)對(duì)象,并且把它傳遞給運(yùn)行時(shí)系統(tǒng)。這個(gè)對(duì)象被叫做異常對(duì)象,它包含了有關(guān)錯(cuò)誤的信息,這些信息包括錯(cuò)誤的類型和在程序發(fā)生錯(cuò)誤時(shí)的狀態(tài)。創(chuàng)建一個(gè)錯(cuò)誤對(duì)象并把它傳遞給運(yùn)行時(shí)系統(tǒng)被叫做拋出異常。
一個(gè)方法拋出異常后,運(yùn)行時(shí)系統(tǒng)就會(huì)試著查找一些方法來(lái)處理它。這些處理異常的可能的方法的集合是被整理在一起的方法列表,這些方法能夠被發(fā)生錯(cuò)誤的方法調(diào)用。這個(gè)方法列表被叫做堆棧調(diào)用(call stack)
運(yùn)行時(shí)系統(tǒng)搜尋包含能夠處理異常的代碼塊的方法所請(qǐng)求的堆棧。這個(gè)代碼塊叫做異常處理器,搜尋首先從發(fā)生的方法開(kāi)始,然后依次按著調(diào)用方法的倒序檢索調(diào)用堆棧。當(dāng)找到一個(gè)相應(yīng)的處理器時(shí),運(yùn)行時(shí)系統(tǒng)就把異常傳遞給這個(gè)處理器。一個(gè)異常處理器要適當(dāng)?shù)乜紴V拋出的異常對(duì)象的類型和異常處理器所處理的異常的類型是否匹配。異常被捕獲以后,異常處理器關(guān)閉。如果運(yùn)行時(shí)系統(tǒng)搜尋了這個(gè)方法的所有的調(diào)用堆棧,而沒(méi)有找到相應(yīng)的異常處理器。
怎么設(shè)計(jì)異常框架
任何的異常都是Throwable類(為何不是接口??),并且在它之下包含兩個(gè)字類Error / Exception,而Error僅在當(dāng)在Java虛擬機(jī)中發(fā)生動(dòng)態(tài)連接失敗或其它的定位失敗的時(shí)候,Java虛擬機(jī)拋出一個(gè)Error對(duì)象。典型的簡(jiǎn)易程序不捕獲或拋出Errors對(duì)象,你可能永遠(yuǎn)不會(huì)遇到需要實(shí)例化Error的應(yīng)用,那就讓我們關(guān)心一下Exception
Exception中比較重要的就是RuntimeException-運(yùn)行時(shí)異常(當(dāng)然這個(gè)名字是存在爭(zhēng)議的,因?yàn)槿魏蔚漠惓6贾粫?huì)發(fā)生在運(yùn)行時(shí)),為什么說(shuō)這個(gè)類時(shí)很重要的呢?因?yàn)樗苯雨P(guān)系到你的異??蚣艿脑O(shè)計(jì),仔細(xì)看RuntimeException
A method is not required to declare in its throws clause any subclasses of RuntimeException that might be thrown during the execution of the method but not caught.
-可能在執(zhí)行方法期間拋出但未被捕獲的 RuntimeException 的任何子類都無(wú)需在 throws 子句中進(jìn)行聲明。
也就是說(shuō)你的應(yīng)用應(yīng)該不去“關(guān)心”(說(shuō)不關(guān)心是不服責(zé)任的,但只是你不應(yīng)該試圖實(shí)例化它的字類)RuntimeException,就如同你不應(yīng)該關(guān)心Error的產(chǎn)生與處理一樣!RuntimeException描述的是程序的錯(cuò)誤引起來(lái)的,因該由程序負(fù)擔(dān)這個(gè)責(zé)任!(<B>從責(zé)任這個(gè)角度看Error屬于JVM需要負(fù)擔(dān)的責(zé)任;RuntimeException是程序應(yīng)該負(fù)擔(dān)的責(zé)任;checked exception 是具體應(yīng)用負(fù)擔(dān)的責(zé)任</B>)
那就有人會(huì)問(wèn),那我該關(guān)心什么!答案就是除了Error與RuntimeException,其他剩下的異常都是你需要關(guān)心的,而這些異常類統(tǒng)稱為Checked Exception,至于Error與RuntimeException則被統(tǒng)稱為Unchecked Exception.
異常的概念就這些了,即使你在網(wǎng)絡(luò)上搜索也就不過(guò)如此,是不是感覺(jué)到有點(diǎn)清晰又有點(diǎn)模糊?那么怎么該如何在這樣單薄而模糊的概念下設(shè)計(jì)J2EE的異常框架呢?
解決方案:J2EE異??蚣?/P>
我們拿一個(gè)模擬的例子來(lái)說(shuō)明異??蚣艿脑O(shè)計(jì)過(guò)程,比如我們要對(duì)外提供doBusiness()這個(gè)業(yè)務(wù)方法
public void doBusiness() throws xxxBusinessException
當(dāng)客戶端調(diào)用這樣的方法的時(shí)候應(yīng)該這樣處理異常(包括處理RuntimeException , checked exception)
<B>記住,無(wú)論如何我們都不希望或者確切的說(shuō)是不應(yīng)該將RuntimeException這樣的異常暴露給客戶的,因?yàn)樗麄儧](méi)有解決這個(gè)問(wèn)題的責(zé)任!</B>
我們暫時(shí)將Struts中的某個(gè)Action看作時(shí)客戶端,其中doExecute(....)要調(diào)用doBusiness()這個(gè)方法
public void doAction(......)
{
try
{
xxx.doBusiness();
}
catch(Exception e)
{
if(e instanceof RuntimeException)
{
// catch runtime exception
// 你可以在這里將捕獲到的RuntimeException
// 將異常通知給某個(gè)負(fù)責(zé)此程序的程序員,讓他知道他
// 自己犯了多么低級(jí)的錯(cuò)誤!
}else
{
//checked exception such as xxxBusinessException
//將這樣的異常暴露給客戶顯示
}
}
}
我們可以這樣設(shè)計(jì)xxxBusinessException
public class xxxBusinessException extends ApplicationException
{
public xxxBusinessException(String s){
super(s);
};
import java.io.PrintStream;
import java.io.PrintWriter;
public class ApplicationException extends Exception {
/** A wrapped Throwable */
protected Throwable cause;
public ApplicationException() {
super("Error occurred in application.");
}
public ApplicationException(String message) {
super(message);
}
public ApplicationException(String message, Throwable cause) {
super(message);
this.cause = cause;
}
// Created to match the JDK 1.4 Throwable method.
public Throwable initCause(Throwable cause) {
this.cause = cause;
return cause;
}
public String getMessage() {
// Get this exception's message.
String msg = super.getMessage();
Throwable parent = this;
Throwable child;
// Look for nested exceptions.
while((child = getNestedException(parent)) != null) {
// Get the child's message.
String msg2 = child.getMessage();
// If we found a message for the child exception,
// we append it.
if (msg2 != null) {
if (msg != null) {
msg += ": " + msg2;
} else {
msg = msg2;
}
}
// Any nested ApplicationException will append its own
// children, so we need to break out of here.
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
// Return the completed message.
return msg;
}
public void printStackTrace() {
// Print the stack trace for this exception.
super.printStackTrace();
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
System.err.print("Caused by: ");
child.printStackTrace();
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public void printStackTrace(PrintStream s) {
// Print the stack trace for this exception.
super.printStackTrace(s);
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
s.print("Caused by: ");
child.printStackTrace(s);
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public void printStackTrace(PrintWriter w) {
// Print the stack trace for this exception.
super.printStackTrace(w);
Throwable parent = this;
Throwable child;
// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
w.print("Caused by: ");
child.printStackTrace(w);
if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}
public Throwable getCause() {
return cause;
}
}
而"聰明"的讀者肯定要問(wèn)我那doBusiness()這個(gè)業(yè)務(wù)方法該如何包裝異常呢?
public void doBusiness() throw xxxBusinessException
{
try
{
execute1(); // if it throw exception1
exexute2(); // if it throw exception 2
.... .....
}
catch (exception1 e1)
{
throw new xxxBusinessException(e1);
}
catch(exception2 e2)
{
throw new xxxBusinessException(e2);
}
........
}
也可以這樣
public void doBusiness() throw xxxBusinessException
{
try
{
execute1(); // if it throw exception1
exexute2(); // if it throw exception 2
.... .....
}
catch (Exception e)
{
// 注意很多應(yīng)用在這里根本不判斷異常的類型而一股腦的采用
// throw new xxxBusinessException(e);
// 而這樣帶來(lái)的問(wèn)題就是xxxBusinessException"吞掉了"RuntimeException
// 從而將checked excption 與unchecked exception混在了一起!
// 其實(shí)xxxBusinessException屬于checked excpetion ,它根本不應(yīng)該也不能夠理睬RuntimeException
if(! e instanceof RuntimeException) throw new xxxBusinessException(e);
}
}
總結(jié)
1。JAVA的異常分為兩類: checked exception & unchecked excpetion
2。應(yīng)用開(kāi)發(fā)中產(chǎn)生的異常都應(yīng)該集成自Exception 但都屬于checked excpetion類型
3。應(yīng)用中的每一層在包裝并傳遞異常的時(shí)候要過(guò)濾掉RuntimeException!
4。從責(zé)任這個(gè)角度看Error屬于JVM需要負(fù)擔(dān)的責(zé)任;RuntimeException是程序應(yīng)該負(fù)擔(dān)的責(zé)任;checked exception 是具體應(yīng)用負(fù)擔(dān)的責(zé)任
5。無(wú)論如何我們都不希望或者確切的說(shuō)是不應(yīng)該將RuntimeException這樣的異常暴露給客戶的,因?yàn)樗麄儧](méi)有解決這個(gè)問(wèn)題的責(zé)任!
posted @ 2006-03-02 20:50 killvin| 編輯 收藏
Nasted Class 的介紹,請(qǐng)?jiān)斠?jiàn)參考
今天討論的不是不是內(nèi)部類的概念,而是具體使用的一個(gè)場(chǎng)景-如何在內(nèi)部類中返回外部對(duì)象
看一段代碼
import java.util.LinkedList;
import java.util.List;
public class OuterClass
{
private List listeners = new LinkedList();
public void addListeners(IListener listener)
{
this.listeners.add(listener);
}
private OuterClass outer = this; (1)
private class InnterClass
{
public void publish()
{
//將事件發(fā)布出去 (2)
for(int i=0;i < listeners.size();i++)
{
IListener listener = (IListener) listeners.get(i);
listener.receiveEvent(outer);
}
}
}
public void execute()
{
InnterClass in = new InnterClass(); (3)
in.publish();
}
}
public interface IListener
{
public void receiveEvent(OuterClass obj);
}
你可能覺(jué)得這個(gè)例子很別扭,在哪里讓你覺(jué)得難受呢?其實(shí)問(wèn)題的關(guān)鍵就在于接口IListener的定義,這里需要給receiveEvent方法傳遞的參數(shù)是外部對(duì)象?。▌e激動(dòng),下面我會(huì)說(shuō)明需要傳遞的一個(gè)場(chǎng)景)
場(chǎng)景
在一個(gè)GUI系統(tǒng)中,我們要在畫(huà)板WorkSpace(WorkSpace實(shí)現(xiàn)了IListener接口)上產(chǎn)生一顆樹(shù),但樹(shù)中的每個(gè)節(jié)點(diǎn)的產(chǎn)生(繪圖)是我們不知道的算法,系統(tǒng)只為我們提供了一些繪圖的接口,并返回元素的句柄!看來(lái)我們需要"包裝"一下這個(gè)繪圖的句柄Brush(其實(shí)我把它叫做筆刷,因?yàn)樗恢廊绾?刷"出圖像來(lái),就這點(diǎn)本事?。┎?duì)外提供節(jié)點(diǎn)Node這樣一個(gè)通用的類。
此時(shí)Node與Brush的關(guān)系就很微妙了,不過(guò)我們可以拋開(kāi)這些外表,看到Node與Brush其實(shí)就是外部類與內(nèi)部類的關(guān)系!-第一步完成了:確定了兩者的關(guān)系
然而,事情沒(méi)有這么簡(jiǎn)單,Node類必須處理一些事件,而這些事件理所當(dāng)然只有Brush能夠看懂,而Node根本不知道這樣的事件處理過(guò)程,現(xiàn)在有兩個(gè)辦法:辦法一,讓Node實(shí)現(xiàn)Brush所有的事件;辦法二,把Brush返回回去,讓它來(lái)處理自己的事件,看來(lái)辦法二是個(gè)好主意,因?yàn)槲铱梢圆魂P(guān)心事件的種類?。?STRONG>第二步完成了:確定了事件處理的責(zé)任
還沒(méi)完呢,你肯定不希望畫(huà)板WorkSpace面對(duì)的是繪圖的句柄Brush這樣的對(duì)象,相反你只希望WokSpace只知道Node的存在!IListener接口中receiveEvent方法的參數(shù)定義為OuterClass 就由此而來(lái)!-第三步完成:接口的定義
public interface IListener
{
public void receiveEvent(OuterClass obj);
}
既然說(shuō)清楚了這個(gè)問(wèn)題(應(yīng)該比較清楚了吧?)那改如何實(shí)現(xiàn)這樣一個(gè)蹩腳而有無(wú)可奈何的設(shè)計(jì)呢?讓我們回憶一下內(nèi)部類,內(nèi)部類擁有訪問(wèn)外部類的方法與屬性的權(quán)限
private OuterClass outer = this; - 這個(gè)對(duì)外部類的引用就是為內(nèi)部類的訪問(wèn)準(zhǔn)備的
private class InnterClass
{
public void publish()
{
//將事件發(fā)布出去
for(int i=0;i < listeners.size();i++)
{
IListener listener = (IListener) listeners.get(i);
listener.receiveEvent(outer); - 這里不可以返回this,因?yàn)閠his代表的是內(nèi)部類自己
}
}
參考
Java Nested class http://blog.csdn.net/Killvin/archive/2006/01/10/574983.aspx
初識(shí)Java內(nèi)部類 http://blog.csdn.net/killvin/archive/2006/01/10/574991.aspx
posted @ 2006-03-02 20:49 killvin| 編輯 收藏
java代碼: ![]() |
1 Session session = ...; 2 Transaction tx = ...; 3 4 Parent parent = (Parent) session.load(Parent.class, id); 5 6 Child child = new Child(); 7 child.setParent(parent); 8 child.setName("sun"); 9 10 parent.addChild(child); 11 s.update(parent); 12 13 s.flush(); 14 tx.commit(); 15 s.close(); |
在上例中,程序并沒(méi)有顯式的session.save(child); 那么Hibernate需要知道child究竟是一個(gè)臨時(shí)對(duì)象,還是已經(jīng)在數(shù)據(jù)庫(kù)中有的持久對(duì)象。如果child是一個(gè)新創(chuàng)建的臨時(shí)對(duì)象(本例中就是這種情況),那么Hibernate應(yīng)該自動(dòng)產(chǎn)生session.save(child)這樣的操作,如果child是已經(jīng)在數(shù)據(jù)庫(kù)中有的持久對(duì)象,那么Hibernate應(yīng)該自動(dòng)產(chǎn)生session.update(child)這樣的操作。
因此我們需要暗示一下Hibernate,究竟child對(duì)象應(yīng)該對(duì)它自動(dòng)save還是update。在上例中,顯然我們應(yīng)該暗示Hibernate對(duì)child自動(dòng)save,而不是自動(dòng)update。那么Hibernate如何判斷究竟對(duì)child是save還是update呢?它會(huì)取一下child的主鍵屬性 child.getId() ,這里假設(shè)id是 java.lang.Integer類型的。如果取到的Id值和hbm映射文件中指定的unsave-value相等,那么Hibernate認(rèn)為child是新的內(nèi)存臨時(shí)對(duì)象,發(fā)送save,如果不相等,那么Hibernate認(rèn)為child是已經(jīng)持久過(guò)的對(duì)象,發(fā)送update。
unsaved-value="null" (默認(rèn)情況,適用于大多數(shù)對(duì)象類型主鍵 Integer/Long/String/...)
當(dāng)Hibernate取一下child的Id,取出來(lái)的是null(在上例中肯定取出來(lái)的是null),和unsaved-value設(shè)定值相等,發(fā)送save(child)
當(dāng)Hibernate取一下child的id,取出來(lái)的不是null,那么和unsaved-value設(shè)定值不相等,發(fā)送update(child)
例如下面的情況:
java代碼: ![]() |
1 Session session = ...; 2 Transaction tx = ...; 3 4 Parent parent = (Parent) session.load(Parent.class, id); 5 Child child = (Child) session.load(Child.class, childId); 6 7 child.setParent(parent); 8 child.setName("sun"); 9 10 parent.addChild(child); 11 s.update(parent); 12 13 s.flush(); 14 tx.commit(); 15 s.close(); |
child已經(jīng)在數(shù)據(jù)庫(kù)中有了,是一個(gè)持久化的對(duì)象,不是新創(chuàng)建的,因此我們希望Hibernate發(fā)送update(child),在該例中,Hibernate取一下child.getId(),和unsave-value指定的null比對(duì)一下,發(fā)現(xiàn)不相等,那么發(fā)送update(child)。
BTW: parent對(duì)象不需要操心,因?yàn)槌绦蝻@式的對(duì)parent有l(wèi)oad操作和update的操作,不需要Hibernate自己來(lái)判斷究竟是save還是update了。我們要注意的只是child對(duì)象的操作。另外unsaved-value是定義在Child類的主鍵屬性中的。
java代碼: ![]() |
1 <class name="Child" table="child"> 2 <id column="id" name="id" type="integer" unsaved-value="null"> 3 <generator class="identity"/> 4 </id> 5 ... 6 </class> |
如果主鍵屬性不是對(duì)象型,而是基本類型,如int/long/double/...,那么你需要指定一個(gè)數(shù)值型的unsaved-value,例如:
java代碼: ![]() |
1 unsaved-null="0" |
在此提醒大家,很多人以為對(duì)主鍵屬性定義為int/long,比定義為Integer/Long運(yùn)行效率來(lái)得高,認(rèn)為基本類型不需要進(jìn)行對(duì)象的封裝和解構(gòu)操作,因此喜歡把主鍵定義為int/long的。但實(shí)際上,Hibernate內(nèi)部總是把主鍵轉(zhuǎn)換為對(duì)象型進(jìn)行操作的,就算你定義為int/long型的,Hibernate內(nèi)部也要進(jìn)行一次對(duì)象構(gòu)造操作,返回給你的時(shí)候,還要進(jìn)行解構(gòu)操作,效率可能反而低也說(shuō)不定。因此大家一定要扭轉(zhuǎn)一個(gè)觀點(diǎn),在Hibernate中,主鍵屬性定義為基本類型,并不能夠比定義為對(duì)象型效率來(lái)的高,而且也多了很多麻煩,因此建議大家使用對(duì)象型的Integer/Long定義主鍵。
unsaved-value="none"和
unsaved-value="any"
主主要用在主鍵屬性不是通過(guò)Hibernate生成,而是程序自己setId()的時(shí)候。
在這里多說(shuō)一句,強(qiáng)烈建議使用Hibernate的id generator,或者你可以自己擴(kuò)展Hibernate的id generator,特別注意不要使用有實(shí)際含義的字段當(dāng)做主鍵來(lái)用!例如用戶類User,很多人喜歡用用戶登陸名稱做為主鍵,這是一個(gè)很不好的習(xí)慣,當(dāng)用戶類和其他實(shí)體類有關(guān)聯(lián)關(guān)系的時(shí)候,萬(wàn)一你需要修改用戶登陸名稱,一改就需要改好幾張表中的數(shù)據(jù)。偶合性太高,而如果你使用無(wú)業(yè)務(wù)意義的id generator,那么修改用戶名稱,就只修改user表就行了。
由這個(gè)問(wèn)題引申出來(lái),如果你嚴(yán)格按照這個(gè)原則來(lái)設(shè)計(jì)數(shù)據(jù)庫(kù),那么你基本上是用不到手工來(lái)setId()的,你用Hibernate的id generator就OK了。因此你也不需要了解當(dāng)
unsaved-value="none"和
unsaved-value="any"
究竟有什么含義了。如果你非要用assigned不可,那么繼續(xù)解釋一下:
unsaved-value="none" 的時(shí)候,由于不論主鍵屬性為任何值,都不可能為none,因此Hibernate總是對(duì)child對(duì)象發(fā)送update(child)
unsaved-value="any" 的時(shí)候,由于不論主鍵屬性為任何值,都肯定為any,因此Hibernate總是對(duì)child對(duì)象發(fā)送save(child)
大多數(shù)情況下,你可以避免使用assigned,只有當(dāng)你使用復(fù)合主鍵的時(shí)候不得不手工setId(),這時(shí)候需要你自己考慮究竟怎么設(shè)置unsaved-value了,根據(jù)你自己的需要來(lái)定。
BTW: Gavin King強(qiáng)烈不建議使用composite-id,強(qiáng)烈建議使用UserType。
因此,如果你在系統(tǒng)設(shè)計(jì)的時(shí)候,遵循如下原則:
1、使用Hibernate的id generator來(lái)生成無(wú)業(yè)務(wù)意義的主鍵,不使用有業(yè)務(wù)含義的字段做主鍵,不使用assigned。
2、使用對(duì)象類型(String/Integer/Long/...)來(lái)做主鍵,而不使用基礎(chǔ)類型(int/long/...)做主鍵
3、不使用composite-id來(lái)處理復(fù)合主鍵的情況,而使用UserType來(lái)處理該種情況。
那么你永遠(yuǎn)用的是unsaved-value="null" ,不可能用到any/none/..了。
posted @ 2006-03-02 20:45 killvin| 編輯 收藏
在Hibernate中,最核心的概念就是對(duì)PO的狀態(tài)管理。一個(gè)PO有三種狀態(tài):
1、未被持久化的VO
此時(shí)就是一個(gè)內(nèi)存對(duì)象VO,由JVM管理生命周期
2、已被持久化的PO,并且在Session生命周期內(nèi)
此時(shí)映射數(shù)據(jù)庫(kù)數(shù)據(jù),由數(shù)據(jù)庫(kù)管理生命周期
3、曾被持久化過(guò),但現(xiàn)在和Session已經(jīng)detached了,以VO的身份在運(yùn)行
這種和Session已經(jīng)detached的PO還能夠進(jìn)入另一個(gè)Session,繼續(xù)進(jìn)行PO狀態(tài)管理,此時(shí)它就成為PO的第二種狀態(tài)了。這種PO實(shí)際上是跨了Session進(jìn)行了狀態(tài)維護(hù)的。
在傳統(tǒng)的JDO1.x中,PO只有前面兩種狀態(tài),一個(gè)PO一旦脫離PM,就喪失了狀態(tài)了,不再和數(shù)據(jù)庫(kù)數(shù)據(jù)關(guān)聯(lián),成為一個(gè)純粹的內(nèi)存VO,它即使進(jìn)入一個(gè)新的PM,也不能恢復(fù)它的狀態(tài)了。
Hibernate強(qiáng)的地方就在于,一個(gè)PO脫離Session之后,還能保持狀態(tài),再進(jìn)入一個(gè)新的Session之后,就恢復(fù)狀態(tài)管理的能力,但此時(shí)狀態(tài)管理需要使用session.update或者session.saveOrUpdate,這就是Hibernate Reference中提到的“requires a slightly different programming model ”
現(xiàn)在正式進(jìn)入本話題:
簡(jiǎn)單的來(lái)說(shuō),update和saveOrUpdate是用來(lái)對(duì)跨Session的PO進(jìn)行狀態(tài)管理的。
假設(shè)你的PO不需要跨Session的話,那么就不需要用到,例如你打開(kāi)一個(gè)Session,對(duì)PO進(jìn)行操作,然后關(guān)閉,之后這個(gè)PO你也不會(huì)再用到了,那么就不需要用update。
因此,我們來(lái)看看上例:
java代碼: ![]() |
1 Foo foo=sess.load(Foo.class,id); 2 foo.setXXX(xxx); 3 sess.flush(); 4 sess.commit(); |
PO對(duì)象foo的操作都在一個(gè)Session生命周期內(nèi)完成,因此不需要顯式的進(jìn)行sess.update(foo)這樣的操作。Hibernate會(huì)自動(dòng)監(jiān)測(cè)到foo對(duì)象已經(jīng)被修改過(guò),因此就向數(shù)據(jù)庫(kù)發(fā)送一個(gè)update的sql。當(dāng)然如果你非要加上sess.update(foo)也不會(huì)錯(cuò),只不過(guò)這樣做沒(méi)有任何必要。
而跨Session的意思就是說(shuō)這個(gè)PO對(duì)象在Session關(guān)閉之后,你還把它當(dāng)做一個(gè)VO來(lái)用,后來(lái)你在Session外面又修改了它的屬性,然后你又想打開(kāi)一個(gè)Session,把VO的屬性修改保存到數(shù)據(jù)庫(kù)里面,那么你就需要用update了。
java代碼: ![]() |
1 // in the first session 2 Cat cat = (Cat) firstSession.load(Cat.class, catId); 3 Cat potentialMate = new Cat(); 4 firstSession.save(potentialMate); 5 6 // in a higher tier of the application 7 cat.setMate(potentialMate); 8 9 // later, in a new session 10 secondSession.update(cat); // update cat 11 secondSession.update(mate); // update mate 12 |
cat和mate對(duì)象是在第一個(gè)session中取得的,在第一個(gè)session關(guān)閉之后,他們就成了PO的第三種狀態(tài),和Session已經(jīng)detached的PO,此時(shí)他們的狀態(tài)信息仍然被保留下來(lái)了。當(dāng)他們進(jìn)入第二個(gè)session之后,立刻就可以進(jìn)行狀態(tài)的更新。但是由于對(duì)cat的修改操作:cat.setMate(potentialMate); 是在Session外面進(jìn)行的,Hibernate不可能知道cat對(duì)象已經(jīng)被改過(guò)了,第二個(gè)Session并不知道這種修改,因此一定要顯式的調(diào)用secondSession.update(cat); 通知Hibernate,cat對(duì)象已經(jīng)修改了,你必須發(fā)送update的sql了。
所以u(píng)pdate的作用就在于此,它只會(huì)被用于當(dāng)一個(gè)PO對(duì)象跨Session進(jìn)行狀態(tài)同步的時(shí)候才需要寫(xiě)。而一個(gè)PO對(duì)象當(dāng)它不需要跨Session進(jìn)行狀態(tài)管理的時(shí)候,是不需要寫(xiě)update的。
再談?wù)?SPAN style="COLOR: #ffa34f">saveOrUpdate的用場(chǎng):
saveOrUpdate和update的區(qū)別就在于在跨Session的PO狀態(tài)管理中,Hibernate對(duì)PO采取何種策略。
例如當(dāng)你寫(xiě)一個(gè)DAOImpl的時(shí)候,讓cat對(duì)象增加一個(gè)mate,如下定義:
java代碼: ![]() |
![]() ...}
2 Session session = ...; 3 Transacton tx = ...; 4 session.update(cat); 5 cat.addMate(mate); 6 tx.commit(); 7 session.close(); 8 }; |
顯然你是需要把Hibernate的操作封裝在DAO里面的,讓業(yè)務(wù)層的程序員和Web層的程序員不需要了解Hibernate,直接對(duì)DAO進(jìn)行調(diào)用。
此時(shí)問(wèn)題就來(lái)了:上面的代碼運(yùn)行正確有一個(gè)必要的前提,那就是方法調(diào)用參數(shù)cat對(duì)象必須是一個(gè)已經(jīng)被持久化過(guò)的PO,也就是來(lái)說(shuō),它應(yīng)該首先從數(shù)據(jù)庫(kù)查詢出來(lái),然后才能這樣用。但是業(yè)務(wù)層的程序員顯然不知道這種內(nèi)部的玄妙,如果他的業(yè)務(wù)是現(xiàn)在增加一個(gè)cat,然后再增加它的mate,他顯然會(huì)這樣調(diào)用,new一個(gè)cat對(duì)象出來(lái),然后就addMate:
java代碼: ![]() |
1 Cat cat = new Cat(); 2 cat.setXXX(); 3 daoimpl.addMate(cat,mate); |
但是請(qǐng)注意看,這個(gè)cat對(duì)象只是一個(gè)VO,它沒(méi)有被持久化過(guò),它還不是PO,它沒(méi)有資格調(diào)用addMate方法,因此調(diào)用addMate方法不會(huì)真正往數(shù)據(jù)庫(kù)里面發(fā)送update的sql,這個(gè)cat對(duì)象必須先被save到數(shù)據(jù)庫(kù),在真正成為一個(gè)PO之后,才具備addMate的資格。
你必須這樣來(lái)操作:
java代碼: ![]() |
1 Cat cat = new Cat(); 2 cat.setXXX(); 3 daoimpl.addCat(cat); 4 daoimpl.addMate(cat, mate); |
先持久化cat,然后才能對(duì)cat進(jìn)行其他的持久化操作。因此要求業(yè)務(wù)層的程序員必須清楚cat對(duì)象處于何種狀態(tài),到底是第一種,還是第三種。如果是第一種,就要先save,再addMate;如果是第三種,就直接addMate。
但是最致命的是,如果整個(gè)軟件分層很多,業(yè)務(wù)層的程序員他拿到這個(gè)cat對(duì)象也可能是上層Web應(yīng)用層傳遞過(guò)來(lái)的cat,他自己也不知道這個(gè)cat究竟是VO,沒(méi)有被持久化過(guò),還是已經(jīng)被持久化過(guò),那么他根本就沒(méi)有辦法寫(xiě)程序了。
所以這樣的DAOImpl顯然是有問(wèn)題的,它會(huì)對(duì)業(yè)務(wù)層的程序員造成很多編程上的陷阱,業(yè)務(wù)層的程序員必須深刻的了解他調(diào)用的每個(gè)DAO對(duì)PO對(duì)象進(jìn)行了何種狀態(tài)管理,必須深刻的了解他的PO對(duì)象在任何時(shí)候處于什么確切的狀態(tài),才能保證編程的正確性,顯然這是做不到的,但是有了saveOrUpdate,這些問(wèn)題就迎刃而解了。
現(xiàn)在你需要修改addMate方法:
java代碼: ![]() |
![]() ...}
2 Session session = ...; 3 Transacton tx = ...; 4 session.saveOrUpdate(cat); 5 cat.addMate(mate); 6 tx.commit(); 7 session.close(); 8 }; |
如上,如果業(yè)務(wù)層的程序員傳進(jìn)來(lái)的是一個(gè)已經(jīng)持久化過(guò)的PO對(duì)象,那么Hibernate會(huì)更新cat對(duì)象(假設(shè)業(yè)務(wù)層的程序員在Session外面修改過(guò)cat的屬性),如果傳進(jìn)來(lái)的是一個(gè)新new出來(lái)的對(duì)象,那么向數(shù)據(jù)庫(kù)save這個(gè)PO對(duì)象。
BTW: Hibernate此時(shí)究竟采取更新cat對(duì)象,還是save cat對(duì)象,取決于unsave-value的設(shè)定。
這樣,業(yè)務(wù)層的程序員就不必再操心PO的狀態(tài)問(wèn)題了,對(duì)于他們來(lái)說(shuō),不管cat是new出來(lái)的對(duì)象,只是一個(gè)VO也好;還是從數(shù)據(jù)庫(kù)查詢出來(lái)的的PO對(duì)象也好,全部都是直接addMate就OK了:
posted @ 2006-03-02 20:44 killvin| 編輯 收藏
StrutsFileUpload
File Upload - Simple Example
HTML
This isn't specific to Struts, but gives a simple example of the HTML required to upload a single file.
Two things are needed in the html page. Firstly, the form needs to specify an enctype of multipart/form-data and secondly an form control of type file.
JSP
The above HTML can be generated using the Struts tags in the following way
<html:form action="/uploadMyFile.do" enctype="multipart/form-data">
Select File: <html:file property="myFile">
<html:submit value="Upload File"/>
</html:form>
ActionForm
The ActionForm needs a property of type FormFile.
Regular ActionForms
import org.apache.struts.upload.FormFile;
public class MyActionForm extends ActionForm {
private FormFile myFile;
public void setMyFile(FormFile myFile) {
this.myFile = myfile;
}
public FormFile getMyFile() {
return myFile;
}
}
Dyna ActionForms
In the struts-config.xml
<form-bean name="myForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="myFile" type="org.apache.struts.upload.FormFile"/>
</form-bean>
Whats Needed in the Action
Nothing special really, just retrieve the FormFile from the ActionForm, as you would any other property, and process it as you like. You can get the file name, size and file contents from the FormFile.
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
MyActionForm myForm = (MyActionForm)form;
// Process the FormFile
FormFile myFile = myForm.getMyFile();
String contentType = myFile.getContentType();
String fileName = myFile.getFileName();
int fileSize = myFile.getFileSize();
byte[] fileData = myFile.getFileData();
...
}
File Upload Configuration
The following parameters can be set in the <controller> element of the struts-config.xml to configure file upload:
bufferSize - The size (in bytes) of the input buffer used when processing file uploads. Default is 4096.
maxFileSize - The maximum size (in bytes) of a file to be accepted as a file upload. Can be expressed as a number followed by a "K", "M", or "G", which are interpreted to mean kilobytes, megabytes, or gigabytes, respectively. Default is 250M.
multipartClass - The fully qualified Java class name of the multipart request handler class to be used with this module. Defaults is org.apache.struts.upload.CommonsMultipartRequestHandler.
tempDir - Temporary working directory to use when processing file uploads.
Above taken from the Configuration section in the User Guide.
Plugging in an Alternative File Upload Mechanism
By default Struts uses Commons File Upload.
Alternative implementations can be plugged as long as they implement the org.apache.struts.upload.MultipartRequestHandler interface and Struts configured to use that implementation by specifying it in the multipartClass parameter in the <controller> element of the struts-config.xml
Fair Warning: The MultipartRequestHandler interface is almost certain to change in a Struts 1.3 or higher release.
posted @ 2006-03-02 20:43 killvin| 編輯 收藏
我們更應(yīng)該將php看作是一個(gè)語(yǔ)言,和python同樣優(yōu)秀(當(dāng)然php和python的定位不同,也就是因?yàn)檫@樣的定位,而讓人產(chǎn)生的錯(cuò)覺(jué)!?。┤绻鸓hp將自己定位如python一樣!并在語(yǔ)言這個(gè)級(jí)別更貼近面向?qū)ο蟮乃季S模式,那Python也許就不會(huì)如此的火爆!
看來(lái)php之父并沒(méi)有將語(yǔ)言向python靠攏的意思,也就是說(shuō)這樣的語(yǔ)言目前的生存空間僅僅只限于服務(wù)器端的腳本!這是它的領(lǐng)地!但除非是它閉著眼鏡,不然沒(méi)有人會(huì)愿意看到html的代碼里寫(xiě)這<?php>這樣的代碼!這就好比是在沒(méi)有webwork 、struts這樣優(yōu)秀的web框架出現(xiàn)之前,jsp讓人惡心的原因,如果Php的領(lǐng)域沒(méi)有這樣的MVC框架出現(xiàn),那我情愿還是選擇jsp!!出于學(xué)習(xí)我會(huì)選擇Python,但永遠(yuǎn)不會(huì)選擇php......
告訴我你知道的php世界里優(yōu)秀的web框架!也許我會(huì)改變看法!但我不會(huì)選擇重新發(fā)明輪子??!
posted @ 2006-03-02 20:26 killvin| 編輯 收藏
You can download the current version of Thinking in Python here. This includes the BackTalk comment collection system that I built in Zope.
The page describing this project is here.
The current version of the book is 0.1. This is a preliminary release; please note that not all the chapters in the book have been translated.
The source code is in the download package. When you unzip everything (remember to use the -a flag if you're on Unix), the code will be put into subdirectories for each chapter.
This is not an introductory Python book. This book assumes you've learned the basics of Python elsewhere. I personally like Learning Python by Lutz & Ascher, from O'Reilly. Although it does not cover all the Python 2.0, 2.1 and 2.2 features that I use in this book, most books don't at this point.
However, Learning Python is not exactly a beginning programmer's book, either (although it's possible if you're dedicated). If you're just getting started with programming you might try the free, downloadable A Byte of Python.
posted @ 2006-03-02 20:23 killvin| 編輯 收藏
Python是一種不但成熟而且功能也十分強(qiáng)大的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言。它的功能性現(xiàn)在已經(jīng)可以與Java相媲美了。盡管Python有著這樣或者那樣的優(yōu)點(diǎn),但是它仍然面對(duì)著這樣的一種現(xiàn)實(shí):真正了解Python的人給予了它很高的評(píng)價(jià),但是實(shí)際上真正了解它的人并不多。在本篇文章里,我將會(huì)向您介紹一系列的Python編程資源,這樣您就可以對(duì)這種編程語(yǔ)言有更多的了解,并且能夠逐步的開(kāi)始使用這個(gè)優(yōu)秀的編程語(yǔ)言了。
開(kāi)始的第一個(gè)步驟
如果您是剛剛開(kāi)始了解Python編程語(yǔ)言,你現(xiàn)在就需要一套Python編程軟件,這樣能夠讓你更好的掌握它。正式的Python軟件中包括了程序指令行,圖形化的用戶界面,范例程序代碼以及一整套的相關(guān)文件。還有另外一個(gè)版本的Python軟件,它的正式名稱是ActivePython。這個(gè)叫做ActivePython的版本是由ActiveState公司提供的。ActiveState是生產(chǎn)Python軟件工具以及相關(guān)軟件的一家公司。但是,這兩種不同的版本區(qū)別何在呢?
ActivePython版本對(duì)于Windows,Linux, 以及Solaris操作系統(tǒng)的二進(jìn)制形式是可以直接使用的。但是常規(guī)的Python軟件雖然比ActivePython支持的操作系統(tǒng)要稍微多一些,但是卻只能夠作為這些操作系統(tǒng)的源代碼來(lái)進(jìn)行下載。ActivePython版本比常規(guī)的Python軟件增加了一些內(nèi)容,并且附帶有更大的標(biāo)準(zhǔn)資源庫(kù)。如果對(duì)于Python軟件來(lái)說(shuō)您僅僅還處于入門(mén)階段的話,我推薦您應(yīng)該跳過(guò)對(duì)ActivePython的學(xué)習(xí)。
當(dāng)你安裝了Python軟件之后,你會(huì)希望掌握它的編程方法,除非你只是喜歡單純的在你的桌面上增加一個(gè)很少使用的可愛(ài)快捷方式而已。在國(guó)際互聯(lián)網(wǎng)上已經(jīng)有了不少關(guān)于Python編程語(yǔ)言的使用指南,請(qǐng)看下面的這些內(nèi)容:
-
正式的Python文件中包含了范圍很大的使用指南,并且對(duì)您來(lái)說(shuō),可能是首選的應(yīng)該瀏覽的網(wǎng)址。
-
Python即時(shí)通是一個(gè)“Python編程語(yǔ)言的最快的速成班”,這個(gè)網(wǎng)址讓學(xué)習(xí)者通過(guò)在一些頁(yè)面上對(duì)一些程序代碼范例進(jìn)行結(jié)構(gòu),輸入,輸出,分類以及變量的控制來(lái)熟悉這種編程語(yǔ)言。
-
投身于Python編程語(yǔ)言的世界是一個(gè)綜合性的Python軟件使用指南。它是以電子書(shū)的形式來(lái)與大家見(jiàn)面的。這款電子書(shū)是為了那些有經(jīng)驗(yàn)的使用Perl, Java,或者 Visual Basic編程語(yǔ)言的軟件設(shè)計(jì)人員轉(zhuǎn)向使用Python而編寫(xiě)的,所以它是很有針對(duì)性的。
-
Python編程語(yǔ)言的全方位接觸是一篇在UnixWorld上登出的時(shí)間已經(jīng)比較久的有關(guān)Python編程語(yǔ)言的文章。這篇文章向讀者們講述了如何使用Python編程語(yǔ)言來(lái)完成一些比較簡(jiǎn)單的小任務(wù),比如說(shuō)編制一個(gè)善意的電子郵件玩笑軟件來(lái)讓你的朋友們嚇一跳或者大吃一驚。
有關(guān)Python編程語(yǔ)言總的說(shuō)明以及資源
如果您已經(jīng)開(kāi)始接觸Python編程語(yǔ)言并且已經(jīng)有了一定的使用Python進(jìn)行程序設(shè)計(jì)的經(jīng)驗(yàn)之后,您可能會(huì)在這個(gè)過(guò)程中產(chǎn)生一些問(wèn)題,或者您會(huì)希望得到有關(guān)Python編程語(yǔ)言更多的相關(guān)資料。為了滿足您這方面的需要,我會(huì)向您提供一些網(wǎng)絡(luò)上的資源作為您的文獻(xiàn)資料庫(kù)。下面列出的這些條都是其中比較好的一些網(wǎng)絡(luò)資源:
-
Parnassus山的拱頂是一個(gè)巨大的Python程序代碼庫(kù),其中包含了成千上萬(wàn)可以使用的Python程序模塊。這些程序模塊中有程序設(shè)計(jì),圖形化處理方法以及國(guó)際互聯(lián)網(wǎng)程序設(shè)計(jì)數(shù)據(jù)庫(kù)。在這個(gè)站點(diǎn)上還有一些已經(jīng)完成的應(yīng)用軟件,并且可以作為程序源代碼讓您下載下來(lái)。
-
Python號(hào)星際旅行船是Digital Creations公司制作的一個(gè)有關(guān)Python編程語(yǔ)言的免費(fèi)網(wǎng)絡(luò)社區(qū)。其中包含了總的數(shù)據(jù)信息資料庫(kù),并且還有成員或者“其星際旅行船宇航員”目錄,在這里能夠和一些Python編程高手進(jìn)行交流。
- O’Reily網(wǎng)絡(luò)的網(wǎng)絡(luò)站點(diǎn)ONLamp.com中擁有關(guān)于Python程序開(kāi)發(fā)的部分,在這個(gè)部分中,學(xué)習(xí)者能夠找到有關(guān)的一些新聞,論壇,問(wèn)題解答留言板以及許多相關(guān)的文章。
- Faqts.com中有一個(gè)Python程序設(shè)計(jì)知識(shí)數(shù)據(jù)庫(kù),其中包含了可以隨意查詢的有關(guān)Python程序設(shè)計(jì)的問(wèn)題以及解決方法。這些資料都是使用過(guò)Python語(yǔ)言的程序設(shè)計(jì)人員提供的。
- Python-URL!是Dr.Dobb周刊的電子郵件摘要,其中包含了與Python程序設(shè)計(jì)語(yǔ)言相關(guān)的新聞,公告,以及國(guó)際互聯(lián)網(wǎng)新聞組活動(dòng)。
- 有不少針對(duì)Python編程語(yǔ)言的電子郵件討論列表。如果您不能在國(guó)際互聯(lián)網(wǎng)上找到您所需要的答案,您可以通過(guò)這種方法從遠(yuǎn)方獲取正確的解決方法。
一些植入Python軟件的有用資源
Python編程語(yǔ)言擁有極好的擴(kuò)充性,并且是一種很好的腳本語(yǔ)言。Python作為編程語(yǔ)言能夠非常好的植入大量的應(yīng)用軟件。這是近來(lái)有關(guān)Python編程語(yǔ)言活動(dòng)的中心內(nèi)容,我們能夠從theKompany中的VeePee了解到更多的信息。VeePee是一種使用圖形用戶界面的腳本環(huán)境,這是被設(shè)計(jì)用來(lái)植入Linux GNOME或者 KDE應(yīng)用軟件,并且能夠?qū)@兩種應(yīng)用軟件提供腳本支持。我要一再提示您的是,ActiveState對(duì)于在.NET中使用Python編程語(yǔ)言擁有經(jīng)過(guò)實(shí)驗(yàn)室檢驗(yàn)的具體經(jīng)驗(yàn)。這樣就允許Python編程語(yǔ)言能夠繼承并且訪問(wèn)在.NET框架中的對(duì)象,并且為其它的.NET編程語(yǔ)言提供了一種腳本支持。
IDE(集成開(kāi)發(fā)環(huán)境)以及編輯器
就像大家知道的那樣,我是一個(gè)沉迷于IDE的人:當(dāng)我編制程序的時(shí)候,如果有code completion,彈出式對(duì)話框,菜單以及工具條,這樣我才會(huì)感覺(jué)舒服一些。我清除的知道在這個(gè)世界上還有許許多多像我一樣的人。很幸運(yùn)的一點(diǎn)是,對(duì)我們這些人來(lái)說(shuō),雖然我們沉迷于此,但是這個(gè)世界上有數(shù)量繁多的非常優(yōu)秀的Python軟件的IDE能夠供我們使用,雖然其中的相當(dāng)大一部分并不是免費(fèi)的:
-
PythonWorks軟件作品是一個(gè)具有商業(yè)品質(zhì)的IDE。它具有一個(gè)Tkinter的圖形化用戶界面,程序代碼倉(cāng)庫(kù),程序調(diào)試器,“聰明的”編輯器以及在線幫助功能。并且它是同時(shí)支持windows,Linux,以及Solaris這三種操作系統(tǒng)的。其零售價(jià)格為395美元。其中還包括免費(fèi)的評(píng)估服務(wù)。
- Wing IDE是一個(gè)用戶化的IDE,它能夠支持宏,code completion,多面手程序調(diào)試器以及源文件管理工具。Wing對(duì)于Linux 以及Windows操作系統(tǒng)的零售價(jià)格大約為100美元,但是對(duì)于使用公開(kāi)化源程序來(lái)說(shuō)是免費(fèi)提供的?,F(xiàn)在,免費(fèi)版本已經(jīng)可以從多種渠道獲得了。
- PythonWin是一個(gè)免費(fèi)的只能在Windows操作系統(tǒng)中使用的圖形化用戶界面創(chuàng)建工具。這個(gè)工具向程序設(shè)計(jì)人員提供了一個(gè)界面資料庫(kù),這個(gè)資料庫(kù)只是針對(duì)微軟公司的系列產(chǎn)品的。
- 從我們?cè)贏ctiveState公司中的朋友(你能證明他們百分之一百的熱愛(ài)Python語(yǔ)言么?),我們能夠獲得免費(fèi)的,經(jīng)過(guò)實(shí)驗(yàn)室驗(yàn)證的插件IDE程序。這些程序都是為Visual Studio.NET特別設(shè)計(jì)的,并且已經(jīng)被命名為Visual Python。請(qǐng)不要把Visual Python和theKompany的VeePee軟件混為一談,它們是兩個(gè)完全不同的產(chǎn)品。
在本文中提到的這些資源能夠幫助你正式的開(kāi)始使用Python語(yǔ)言進(jìn)行程序設(shè)計(jì)的工作,并且還能夠幫助你找到獲取這些資源的途徑。你只要記住的一點(diǎn)是:沒(méi)有人喜歡Spanish Inquisitionn(西班牙宗教法庭,在1480-1834年之間存在的天主教法庭,以殘酷迫害異端著稱)。你不會(huì)真的期望只是通過(guò)一篇文章就能夠獲取所有有關(guān)Python編程語(yǔ)言的知識(shí)吧?這種愿望是非常不切合實(shí)際的。
posted @ 2006-03-02 20:22 killvin| 編輯 收藏
posted @ 2006-03-02 20:20 killvin| 編輯 收藏
如果你以前只會(huì)用 Shell Script 或是 DOS Batch File 而想學(xué)些其他的東西,Python 會(huì)是你的首選,如果你己經(jīng)會(huì) Perl 或是 Tcl 或是別的什么,那 Python 會(huì)令你改變對(duì) scripting language 的想法。
為什么要學(xué) Python?
答:好玩。就是這樣簡(jiǎn)單。無(wú)論是學(xué) Python 還是用 Python,都是一件賞心樂(lè)事。當(dāng)你寫(xiě) shell scripts 寫(xiě)得鬼哭神號(hào)時(shí),當(dāng)你改 perl scripts 改得頭昏腦漲時(shí),有沒(méi)有想過(guò)寫(xiě) script 其實(shí)是很好玩的一件事。你可能從來(lái)不相信當(dāng)你寫(xiě)一套嚴(yán)肅而功能強(qiáng)大的程式,你可以用一個(gè)如此好玩的程式語(yǔ)言來(lái)開(kāi)發(fā)。更難令你相信的是,就算在程式開(kāi)發(fā)的后期,甚至是幾個(gè)月以后當(dāng)你再次想修改它的時(shí)候,你依然都會(huì)覺(jué)得是一件好玩的事。
Python 能做什么?
答:倒不如問(wèn),Python 不能做什么? Python 已經(jīng)差不多把一個(gè) scripting language 作為整合工具 (gluing tool) 的強(qiáng)大功能完全發(fā)揮了出來(lái),任何程式,只要有個(gè)給 Python 用的接口,Python 就可以把它據(jù)為己用,和其他的程式一塊使用。而且
· Python 有發(fā)展 XML 的大型函式庫(kù),并開(kāi)始有大型系統(tǒng)的構(gòu)建初型。 · 用 Python 寫(xiě)的 Zope,可以用來(lái)架設(shè)整個(gè)網(wǎng)站 · Python 語(yǔ)言自己是用 C 來(lái)寫(xiě)的,但現(xiàn)已有用純 Java 寫(xiě)的 Python 語(yǔ)言實(shí)現(xiàn),近期更有用微軟 .NET 方式實(shí)現(xiàn)的 Python 翻譯器,由此證明了 Python 語(yǔ)言定義的高度完整。 · Python 已移植到許多的操作平臺(tái)上,包括 Linux、Windows、HP、Solaris、Irix、AIX、BeOS、甚至是 Cray。幾乎和 Perl 一樣多。 ·由于 Python 本身是 object oriented,所以很容易和 C++,Java 等整合,尤其在 Visual 當(dāng)?shù)赖?Windows 系統(tǒng)。這點(diǎn)要比 Perl 好許多。
和其他語(yǔ)言的比較
一般的說(shuō)法的這樣的:
- Shell script 太舊了,無(wú)論如何不能用來(lái)寫(xiě)程式。
- Perl 擅長(zhǎng)做服務(wù)器的管理,因?yàn)樗淖执幚砉δ芴貏e強(qiáng)大,同時(shí)有全面的編程接口和操作系統(tǒng)相連。自己用沒(méi)問(wèn)題,就是不懂人家在寫(xiě)什么。
- PHP 擅長(zhǎng)于網(wǎng)頁(yè),因?yàn)樗梢郧度朐?HTML 文件中并支援各類資料庫(kù)。但一離開(kāi)網(wǎng)頁(yè)就左支右絀。
- Python 特別適合一般的需求,因?yàn)樗Z(yǔ)法簡(jiǎn)明,容易維護(hù),有很多模組可用,而且容易做出圖形介面。但它并不是 object oriented 并不純,速度也較 Perl 慢一些。
- Tcl/Tk 基本變數(shù)形態(tài)只有文字串,每次算術(shù)都是從文字變數(shù)字再變文字,鳴,沒(méi)什么好提的了吧。
- Java 太偉大了,我可不想每次開(kāi)始寫(xiě)程式時(shí)都幻想要完成一個(gè)跨企業(yè)的解決方案,引入幾十個(gè)標(biāo)頭檔,寫(xiě)完了才明白原來(lái)我只需它讀一個(gè)用戶指定的文件,畫(huà)兩條直線就行了。唉,落差太大。
- Ruby 太新了,要正式應(yīng)用是將來(lái)的事。
但事實(shí)上我個(gè)人的感受最深的是它比較好玩的說(shuō)法。雖然像是不認(rèn)真,但一種可以讓人寓編程于娛樂(lè)的程式語(yǔ)言,正是程式語(yǔ)言的設(shè)計(jì)終極嘛。
Python 的作者是數(shù)學(xué)家,而 Perl 的作者則是個(gè)天才程式員。因此這兩種語(yǔ)言的風(fēng)格回異:Python 語(yǔ)法鋪排的很整潔,相同功能的程式由不同人寫(xiě)出來(lái)的樣子都很像,這些一致的、前后呼應(yīng)的程式對(duì)于系統(tǒng)的拓展和整合十分重要。因此閱讀 Python 的程式感覺(jué)上很暢順。Perl 的語(yǔ)法則很濃縮,而且經(jīng)常會(huì)有些意想不到的巧思,可惜這些每每體現(xiàn)在字里行間的妙著對(duì)整個(gè)程式的可讀性帶來(lái)負(fù)面影響。因而一個(gè)短小的 Perl 程式往往令人愛(ài)不釋手,但當(dāng)它越來(lái)越長(zhǎng)時(shí)總會(huì)變成程式員的永痛。
至于PHP,因它的發(fā)展歷史一直是圍繞著 web page,所以做網(wǎng)頁(yè)設(shè)計(jì)是十分方便的,但是寫(xiě)一般的工作則平平無(wú)奇。比如說(shuō)控制執(zhí)行緒,處理進(jìn)程間的訊息傳送以致做圖形用戶介面等都久奉,這是因?yàn)閺?WEB 的角度,這些并不重要:圖形介面,HTML 就己經(jīng)是了,而程式的執(zhí)行和互相合作則是 Web Server 要考慮的事。
我推薦 Python 是因?yàn)槲矣X(jué)得它比較適合用作一般性程式編寫(xiě)和系統(tǒng)整合,尤其是在科學(xué)和教育領(lǐng)域中。我并不是說(shuō)大家沒(méi)本事學(xué)好 Perl,只是很多時(shí)候我們并不需要用到 Perl 的精妙之處,更多的時(shí)候用一個(gè)清楚直接的描述要比用一個(gè)智力題級(jí)的招數(shù)更有好處。除了語(yǔ)法的設(shè)計(jì)較為整潔外,Python 還有很好的對(duì)電腦圖形的支援,也有十分快的數(shù)學(xué)陣列模組。
而它最方便的地方是很容易的把其他的程式整合在一起,譬如說(shuō)你有個(gè)幾年前寫(xiě)的 C 程式,只要修改很小的一部份就可以編譯成 Python 可用的模組。事實(shí)上已經(jīng)有自動(dòng)幫你做這些修改的程式了,人們也己為許多各種好用的函式庫(kù)做出了 Python binding,如 OpenGL、GTK、QT、GD、甚至于解方程組的、找頻譜的都有。
而在使用了一段時(shí)間后,我開(kāi)始體會(huì)下面的說(shuō)法:
‘Python 是設(shè)計(jì)出來(lái)的,而 PHP 和 Perl 是累積而來(lái)的?!?/B>
雖然它們各自都有類似的功能,但在使用時(shí)會(huì)發(fā)現(xiàn) Python 的寫(xiě)法總是較為一致,這是因?yàn)?Python 從一開(kāi)始便考慮了它整個(gè)的架構(gòu)。相反,像 Perl 或 PHP 則有很多功能都是后來(lái)慢慢加上去的,所以到后期 Perl 的發(fā)展越來(lái)越難,以致 Perl 6 幾乎要從頭設(shè)計(jì)。而 PHP 則現(xiàn)在才開(kāi)始頭痛于構(gòu)思新的函數(shù)名稱 (所有的 PHP 函數(shù)都是全域定義的,所以每加一個(gè)函數(shù)都有可能和已經(jīng)定義了的名字重復(fù))。為了解決問(wèn)題,它們各自都開(kāi)始注意加強(qiáng) class, object 的支援。但很明顯的是,在程式成熟后再加這些基本功能會(huì)令整個(gè)語(yǔ)言的框架變得頭重腳輕,無(wú)論是寫(xiě)起來(lái)還是用起來(lái)都有些不穩(wěn)的感覺(jué)。
然而 Python 在一開(kāi)始的時(shí)候就把這些考慮了進(jìn)去:Python 根本就是以物件導(dǎo)向作為設(shè)計(jì)的基礎(chǔ)。因此在加了許許多多的功能和模組后,它的風(fēng)采仍舊,清新依然。
好話說(shuō)了不少,光說(shuō)不練可是不行。參考程式示范區(qū)的實(shí)際例子,看看 Python 到底是怎樣一回事。
posted @ 2006-03-02 20:17 killvin| 編輯 收藏
javascript的調(diào)試相當(dāng)繁瑣,alert不能有效地起到調(diào)試作用,原因在于:
1, alert只能在開(kāi)發(fā)期使用,不能在產(chǎn)品交付中繼續(xù)alert debug info
2, 就算在開(kāi)發(fā)期,頻繁的alert會(huì)導(dǎo)致調(diào)試效率低下。
一個(gè)簡(jiǎn)單的log就會(huì)有很大幫助。下面就是我在現(xiàn)實(shí)生活中使用的javascript log方法。
把它包含在一個(gè)全局import的js里面,以后代碼就可以采用log()的方式來(lái)進(jìn)行了。
當(dāng)然,若誰(shuí)有時(shí)間改造為log4j那樣的可以按照分類打開(kāi)或關(guān)閉log,再分上info,error什么的log級(jí)別就更好了。不過(guò)下面的簡(jiǎn)單方法就夠我用拉。
common.js
function log(v)
{
var s = "<li><font color=blue>"+new Date()+"</font> "+v+"</li>";
logPanel_log.innerHTML+=s;
}
window.onhelp = function()
{
logPanel.style.display=logPanel.style.display=='none'?"block":"none";
return false;
}
document.write(
"<div id=logPanel style='display:none;text-align:right'>"+
"<button onclick=\"logPanel_log.innerHTML='';\">clear</button> "+
"<button onclick=\"logPanel_log.innerHTML+='<hr>';\">HR</button>"+
"<div id='logPanel_log'></div></div>");
它覆蓋了默認(rèn)的IE 按F1鍵顯示IE help的行為,現(xiàn)在按下F1就能夠顯示log信息了。
摘自 redsaga滿江紅 http://www.blogcn.com/User6/caoxg/blog/5705836.html
posted @ 2006-03-02 20:15 killvin| 編輯 收藏
JavaScript說(shuō)分明
http://taiwan.cnet.com/enterprise/technology/0,2000062852,20103386,00.htm
朱仲傑撰 2005/12/28
最近因?yàn)锳JAX受到Google等網(wǎng)路服務(wù)業(yè)者的愛(ài)用而聲名大噪。也讓這個(gè)其實(shí)存在很久的程式語(yǔ)言再度成為討論話題。
JavaScript可以說(shuō)是全世界使用最普遍的一個(gè)語(yǔ)言。雖然就統(tǒng)計(jì)資料(註)上來(lái)看,用JavaScript為主的專案數(shù)量只排在第九名,但我相信就應(yīng)用的層面來(lái)看,絕對(duì)遠(yuǎn)超過(guò)Java與.Net。JavaScript也是最讓人混淆的一個(gè)語(yǔ)言,即便是專業(yè)的網(wǎng)頁(yè)工程師,也不見(jiàn)得每位都能正確的了解它。網(wǎng)頁(yè)工程師對(duì)它又愛(ài)又恨,使用者最能體驗(yàn)到它所帶來(lái)的好處,但常常也是被它搞的昏頭轉(zhuǎn)向。到底它是個(gè)什麼樣神奇的語(yǔ)言呢?
JavaScript的前世今生
提到JavaScript,大家第一個(gè)聯(lián)想到的就是Java,但一切的誤解也就從這開(kāi)始。要說(shuō)它跟Java完全沒(méi)關(guān)係嘛,也不盡然。JavaScript原來(lái)的名稱叫LiveScript,是Netscape(網(wǎng)景)為了它的LiveWare平臺(tái)所發(fā)展出來(lái)的一套語(yǔ)言。後來(lái)之所以改名叫JavaScript,主要是因?yàn)楫?dāng)年Netscape與Sun合作,共同開(kāi)發(fā)網(wǎng)頁(yè)上的腳本語(yǔ)言,而剛好Sun正在開(kāi)發(fā)Java語(yǔ)言,初期而且也是以網(wǎng)頁(yè)上的應(yīng)用Java Applet為主,所以LiveScript也就改名為JavaScript。第一個(gè)擁有執(zhí)行JavaScript的瀏覽器Netscape 2.0,發(fā)表日期也跟Java一樣,同樣都是1995年,所以算起來(lái)今年也是JavaScript的十歲生日。
JavaScript的版本非常多種,最原始的是由Netscape一路發(fā)展過(guò)來(lái)的,後來(lái)NetScape把它交給ECMA製定為標(biāo)準(zhǔn)(ECMA-262),而ECMA所製定出來(lái)的稱之為ECMAScript;最喜歡自己也搞一套的微軟,也有自訂的Jscript。理論上,有了標(biāo)準(zhǔn)大家就應(yīng)該要遵守,不過(guò)到目前看來(lái),實(shí)際上並非如此。各家瀏覽器相容的程度不一,造成現(xiàn)在混亂的局面,同一個(gè)網(wǎng)頁(yè)用不同的瀏覽器瀏覽有時(shí)結(jié)果不盡相同。
JavaScript沒(méi)有你想像中的簡(jiǎn)單
JavaScript是屬於prototype-based的一種語(yǔ)言,而prototype-based又是物件導(dǎo)向程式設(shè)計(jì)語(yǔ)言(Object-Oriented Programming Language)的一個(gè)分枝,所以嚴(yán)格說(shuō)起來(lái),JavaScript也是一種物件導(dǎo)向程式設(shè)計(jì)語(yǔ)言。光看到「物件導(dǎo)向」這四個(gè)字,我想很多人頭皮都已經(jīng)開(kāi)始發(fā)麻了,不過(guò)JavaScript之所以不簡(jiǎn)單並不是因?yàn)檫@一點(diǎn),而是因?yàn)樗慕Y(jié)構(gòu)鬆散和型態(tài)鬆散(loose typing)所導(dǎo)致。
你若寫(xiě)過(guò)Java程式的話或許就知道,Java程式必需要Java虛擬機(jī)器(JVM)上執(zhí)行,在執(zhí)行Java程式之前,它必需是被編譯過(guò)的;在編譯的過(guò)程中,Java會(huì)檢查許許多多的條件,例如最基本的語(yǔ)法、變數(shù)的宣告等等。
JavaScript一樣得依存在一個(gè)容器(Container)中才能執(zhí)行,我們常見(jiàn)到的容器就是瀏覽器(Web Browser),跟Java不同的是,JavaScript的程式不需要事先編譯,它是屬於直譯式的語(yǔ)言,你可以把它想像成看到一行程式碼就執(zhí)行一行。因?yàn)樯倭司幾g時(shí)期的檢查,JavaScript就比Java「自由」許多,你可以在網(wǎng)頁(yè)上隨意的位置上安插JavaScript程式、可以隨意的建立新的變數(shù)來(lái)使用;你不用分清楚什麼是數(shù)值,什麼是字串、什麼又是物件,通通可以加加(+)在一起,這就會(huì)造成相當(dāng)不嚴(yán)謹(jǐn)?shù)拈_(kāi)發(fā)過(guò)程。
自由是必需要付出代價(jià)的,前面提到相容性的混亂,在這又有語(yǔ)法結(jié)構(gòu)上的混亂,這下子可以說(shuō)是亂上加亂了。網(wǎng)頁(yè)工程師之所以對(duì)JavaScript又愛(ài)又恨,愛(ài)是因?yàn)橥高^(guò)適當(dāng)?shù)腏avaScript,可以在網(wǎng)頁(yè)上創(chuàng)造出許許多多特殊的效果,讓使用者在瀏覽這個(gè)網(wǎng)頁(yè)時(shí),能有更多的互動(dòng)。恨是因?yàn)槭袌?chǎng)上極少有以JavaScript為主的整合開(kāi)發(fā)工具(IDE),因?yàn)閯倓偹f(shuō)的混亂,造成JavaScript程式很難開(kāi)發(fā)和除錯(cuò)。
JavaScript之所以普及,是因?yàn)閷?xiě)JavaScript程式的使用者,不見(jiàn)得是寫(xiě)Java、C/C++、VB等受過(guò)基本程式設(shè)計(jì)訓(xùn)練的程式設(shè)計(jì)師,往往網(wǎng)頁(yè)的美工人員才是使用JavaScript的大宗。他們不會(huì)也沒(méi)時(shí)間去學(xué)習(xí)完整的JavaScript,而是有需要時(shí)才在網(wǎng)頁(yè)上東加一些、西加一點(diǎn),這些加上去的JavaScript可能是網(wǎng)頁(yè)編輯器所提供的元件、或是網(wǎng)路上分享出來(lái)的程式片段。JavaScript一點(diǎn)都不簡(jiǎn)單,只是大家都很偷懶,用最簡(jiǎn)單的方式來(lái)使用它罷了。
AJAX應(yīng)用為JavaScript注入強(qiáng)心劑
JavaScript十年來(lái)沒(méi)有特別受歡迎,因?yàn)閃WW盛行以來(lái)它和HTML一樣已變成網(wǎng)頁(yè)裡最基本的元素,直到AJAX的出現(xiàn),讓JavaScript大大的受到眾人的注視。AJAX的全名是 Asynchronous JavaScript and XML,JavaScript就是其中之一的主角,AJAX並不是一項(xiàng)新的技術(shù),而是將一些舊有的技術(shù)結(jié)合起來(lái)做一種巧妙的應(yīng)用,賦予網(wǎng)頁(yè)的一股新動(dòng)力。
AJAX這個(gè)名詞最早是出現(xiàn)在Adaptive Path網(wǎng)站上,一篇由 Jesse James Garrett於2005年2月18號(hào)所寫(xiě)的文章中所提出的(http://www.adaptivepath.com/publications/essays/archives/000385.php)。AJAX是客戶端(瀏覽器)的技術(shù),簡(jiǎn)單的說(shuō),就是用JavaScript與後端伺服器做資料的溝通,資料採(cǎi)用XML的格式,JavaScript動(dòng)態(tài)地從後端拿到XML格式的資料,重新整理、重組後再顯示到網(wǎng)頁(yè)上。AJAX基本上是無(wú)關(guān)Java或.Net的,甚至PHP也可以跟AJAX結(jié)合在一起使用。網(wǎng)路上、雜誌裡介紹AJAX的文章相當(dāng)?shù)亩?,在這我就不贅述。在這要提醒大家注意的是,因?yàn)锳JAX,JavaScript又開(kāi)始大量的應(yīng)用在網(wǎng)頁(yè)裡,前面所提及的混亂又被突顯了出來(lái)?;靵y不一定只是負(fù)面的,所謂時(shí)勢(shì)造英雄,我們期待有人能出來(lái)一統(tǒng)江湖。
JavaScript的其它應(yīng)用
JavaScript只能夠運(yùn)用在網(wǎng)頁(yè)上嗎?其實(shí)蘋(píng)果電腦(Apple)除了硬體上的創(chuàng)意外,在作業(yè)系統(tǒng)上的表現(xiàn)一直以來(lái)也是使用者的最愛(ài)。在新的Mac OS X 10.4裡,有個(gè)新的功能叫-Dashboard,它可以讓你執(zhí)行一些小程式,例如月曆、天氣預(yù)報(bào)、地圖查找等。這些小程式稱為Widget,而撰寫(xiě)Widget的主要語(yǔ)言就是JavaScript,當(dāng)然還可以配合HTML、CSS甚至Java Applet。隨著Mac OS X的使用者日益成長(zhǎng),撰寫(xiě)Widget已成為一個(gè)新興的軟體業(yè)。Dashboard其實(shí)不是第一個(gè)實(shí)踐這個(gè)概念的程式,早在Mac OS X 10.2時(shí),就有一個(gè)叫Konfabulator的軟體做出這樣的平臺(tái),在當(dāng)時(shí)大受歡迎。後來(lái)Apple在Mac OS X 10.4內(nèi)建一樣功能的Dashboard時(shí),還飽受外界的批評(píng)和指責(zé),認(rèn)為Apple是抄襲Konfabulator的。隨著Mac OS X直接支援Wedget,Konfabulator漸漸的淡出Mac的舞臺(tái)。不過(guò)Yahoo看上了它,把它給買(mǎi)了下來(lái),而在不久前重新推出Windows/Mac版的Yahoo!Webget,這下Windows的使用者也能享受Widget所帶來(lái)的便利和好處。
下一步
世界上有所謂的Java工程師、C/C++工程師、VB工程師等?,好像沒(méi)有JavaScript工程師這樣的頭銜,我個(gè)人覺(jué)得他應(yīng)該是被需要的。JavaScript其實(shí)並不好學(xué),教育訓(xùn)練是個(gè)商機(jī),開(kāi)發(fā)除錯(cuò)平臺(tái)也是一個(gè)商機(jī)。這年頭流行認(rèn)證,它也是可以著墨的,例如辦理類似SCJP、MCSE這樣的認(rèn)證考式(事實(shí)上是有JavaScript Certification,不過(guò)沒(méi)像其它認(rèn)證這麼有公信和正式就是了)。唯有專門(mén)的訓(xùn)練課程及認(rèn)證才能真正落實(shí)JavaScript的標(biāo)準(zhǔn)化,這樣寫(xiě)出來(lái)的JavaScript程式才不會(huì)相容性不足,造成用某種瀏覽器才能觀看的特定網(wǎng)頁(yè)的情況。
而另一種是像無(wú)障礙網(wǎng)頁(yè)這種的認(rèn)證,若你的網(wǎng)頁(yè)通過(guò)JavaScript相容性審合,那麼在網(wǎng)頁(yè)上就可以放上一個(gè)標(biāo)章,証明你的網(wǎng)頁(yè)是相容於各種瀏覽器的。以上這些如果能由國(guó)際大廠來(lái)推動(dòng),成功的機(jī)會(huì)才會(huì)比較大,好奇的是,這麼多年來(lái),怎麼沒(méi)人想幹這件事?!也許是吃力不討好吧。
註: TIOBE Programming Community Index for December 2005 http://www.tiobe.com/tpci.htm 相關(guān)連結(jié):
ECMA-262
http://www.ecma-international.org/publications/standards/Ecma-262.htm
Spidermonkey
http://www.mozilla.org/js/spidermonkey/
Rhino
http://www.mozilla.org/rhino/
Dashboard
http://www.apple.com/macosx/features/dashboard/
Yahoo!Wedgets
http://widgets.yahoo.com/
posted @ 2006-03-02 20:09 killvin| 編輯 收藏
Buffalo介紹
Web正隨著Amowa/Ajax的引入開(kāi)發(fā)開(kāi)始變得有趣!
Buffalo是Amowa思想實(shí)現(xiàn)的關(guān)鍵組件。Buffalo中定義了Web遠(yuǎn)程調(diào)用的傳輸基礎(chǔ),并且將遠(yuǎn)程調(diào)用對(duì)象完整的序列化到了本地,成為可以被JavaScript編程觸及的對(duì)象。Buffalo中的重要組件 - BuffaloBinding,提供了將JavaScript對(duì)象綁定到HTML元素的能力。這種綁定將是無(wú)侵入的,只需要在HTML元素中加入若干個(gè)不影響排版的屬性,即可將數(shù)據(jù)與界面綁定。
Buffalo1.1之前的版本重要的功能主要集中于遠(yuǎn)程調(diào)用與Java對(duì)象/JavaScript對(duì)象之間的雙向序列化,這個(gè)特性已經(jīng)被眾多的應(yīng)用久經(jīng)考驗(yàn),被認(rèn)為是健壯的。它大大減少了在Java對(duì)象與JavaScript對(duì)象之間需要考慮的細(xì)節(jié),開(kāi)發(fā)者可以更用心地進(jìn)行業(yè)務(wù)設(shè)計(jì)和界面設(shè)計(jì)。1.2版本的推出,引入了新的眾多的特性,包括:新的重新改寫(xiě)的Spring集成;與流行javascript庫(kù)prototype的集成;支持瀏覽器前進(jìn)后退按鈕,等等。Buffalo努力使Web2.0的概念在這個(gè)小小的輕量級(jí)的框架中得到體現(xiàn),讓你的應(yīng)用具備更豐富的表現(xiàn)。
問(wèn)題
可是在使用Buffalo傳輸對(duì)象的過(guò)程中我發(fā)現(xiàn)Buffalo并不能夠很好的傳遞用戶自定義的對(duì)象,不光如此在與作者的討論過(guò)程中我還發(fā)現(xiàn)很多的人對(duì)于Javascript程序的規(guī)范根本不屑一顧,似乎選擇了Javascript本身就是選擇了"自由編程",可是真的如此嗎?
其實(shí)Javascript是一個(gè)比較純粹的OO語(yǔ)言,并不想一些報(bào)道中所說(shuō)的那樣,對(duì)于封裝、繼承、多態(tài)Javascript同樣可以完成,既然它是OO的語(yǔ)言,就理所應(yīng)當(dāng)?shù)陌凑漳撤N規(guī)范來(lái)編寫(xiě)代碼,正如JavaScript說(shuō)分明 中說(shuō)得那樣,編寫(xiě)Javascript不是一件簡(jiǎn)單的事情,關(guān)鍵是很多人亂用了這個(gè)語(yǔ)言,從而導(dǎo)致給很多的朋友以為寫(xiě)Javascript就是很沒(méi)有水準(zhǔn)的事情(偶以前也是如此),但我最近發(fā)現(xiàn)用Javascript這樣的動(dòng)態(tài)語(yǔ)言沒(méi)有一個(gè)很好的語(yǔ)言規(guī)范,你開(kāi)發(fā)出來(lái)的應(yīng)用只能夠停留在小型系統(tǒng)之上,而對(duì)于比較大型的應(yīng)用開(kāi)發(fā),這樣寫(xiě)出來(lái)得代買(mǎi)根本無(wú)法復(fù)用!
再來(lái)說(shuō)說(shuō)Buffalo傳輸對(duì)象的問(wèn)題,以下是我自定義的Node對(duì)象
function Node(_id , _type)
{
//log("create node object!!!");
//============================== property =================================//
//=========================================================================//
var id = _id;
var type = _type; //<- type的出現(xiàn)在OO世界里本身就是背叛
var brush = null //節(jié)點(diǎn)的物理表現(xiàn)句柄
var rList = new Array();//左節(jié)點(diǎn)列表
var lList = new Array();//右節(jié)點(diǎn)列表
var rLine = new Array();//節(jié)點(diǎn)的左線列表
var lLine = new Array();//節(jié)點(diǎn)的右線列表
var x = 0;//節(jié)點(diǎn)的x坐標(biāo)
var y = 0;//節(jié)點(diǎn)的y坐標(biāo)
var m = false; //標(biāo)識(shí)節(jié)點(diǎn)是否可移動(dòng)
var r = false; //標(biāo)識(shí)節(jié)點(diǎn)是否能夠建立聯(lián)系
var name = ""; //節(jié)點(diǎn)的名稱
//================================ method =================================//
//=========================================================================//
this.getType = function()
{
return type;
}
this.setType = function(_t)
{
type = _t;
}
this.setName = function(_n)
{
name = _n;
}
this.getName = function()
{
return name;
}
this.setId = function(_i)
{
id = _i;
}
this.getId = function()
{
return id;
}
}
然而在使用Buffalo的時(shí)候Node對(duì)象根本就無(wú)法傳遞,而導(dǎo)致這個(gè)問(wèn)題的原因竟然是我沒(méi)有"自由的編寫(xiě)Javascript"!其實(shí)問(wèn)題就出在doStructXML 方法上,作者在這里有意的"避開(kāi)"了這個(gè)問(wèn)題,所以在傳遞Node的時(shí)候?qū)τ谄渌接械姆椒˙uffalo是根本就不考慮的,F(xiàn)AINT!
原先
doStructXML : function(data){
var boClass = data[Buffalo.BOCLASS];
var boType = boClass ? boClass : "java.util.HashMap";
var xml = "<map>\n";
xml += "<type>" +boType+ "</type>\n";
for (var i in data){
if (data[i] != boType) {
if (typeof(data[i]) == "function") continue; /* the function shouldn't transfered. */
xml += this.getParamXML(this.dataTypeOf(i),i)+"\n";
xml += this.getParamXML(this.dataTypeOf(data[i]),data[i]) + "\n";
}
}
xml += "</map>\n";
return xml;
},
修改后
doStructXML : function(data){
var boClass = data[Buffalo.BOCLASS];
var boType = boClass ? boClass : "java.util.HashMap";
var xml = "<map>\n";
xml += "<type>" +boType+ "</type>\n";
for (var i in data){
if (data[i] != boType) {
if (typeof(data[i]) == "function")
{
/*判斷方法名稱*/
if(i.substring(0,3) == 'get')
{
var _name = i.substring(3,i.length).toLowerCase();
var _value = data[i]();
//alert("functin name[" + this.dataTypeOf(_name) + "]=" + _name
// + " | value[" + this.dataTypeOf(_value) + "]=" + _value);
xml += this.getParamXML(this.dataTypeOf(_name),_name)+"\n";
xml += this.getParamXML(this.dataTypeOf(_value),_value) + "\n";
}
continue; /* the function shouldn't transfered. */
}
xml += this.getParamXML(this.dataTypeOf(i),i)+"\n";
xml += this.getParamXML(this.dataTypeOf(data[i]),data[i]) + "\n";
}
}
xml += "</map>\n";
return xml;
}
總結(jié)
1。Javascript的編寫(xiě)是否應(yīng)該遵守一定的規(guī)范,其實(shí)屬于程序員自身休養(yǎng)的問(wèn)題,但我還是覺(jué)得復(fù)用JAVA的編碼規(guī)范不是壞事情!
2。時(shí)刻記住Buffalo是建立在burlap協(xié)議的基礎(chǔ)上的,我們應(yīng)該把注意力放在burlap上而不僅僅只是Buffalo!
posted @ 2006-03-02 19:46 killvin| 編輯 收藏
posted @ 2006-03-02 19:24 killvin| 編輯 收藏