Eclipse 快捷鍵大全
類別 命令 鍵序列 說明
C/C++ Source Add Block Comment Ctrl+Shift+/ C/C++ Editor
C/C++ Source Add Include Ctrl+Shift+N C/C++ Editor
C/C++ Source Comment Ctrl+/ C/C++ Editor
C/C++ Source Find Declaration Ctrl+G C/C++ Editor
C/C++ Source Find References Ctrl+Shift+G C/C++ Editor
C/C++ Source Format Ctrl+Shift+F C/C++ Editor
C/C++ Source Go to Matching Bracket Ctrl+Shift+P C/C++ Editor
C/C++ Source Go to next C/C++ member Ctrl+Shift+向下鍵 C/C++ Editor
C/C++ Source Go to previous C/C++ member Ctrl+Shift+向上鍵 C/C++ Editor
C/C++ Source Open Declaration F3 C/C++ Editor
C/C++ Source Open Definition Ctrl+F3 C/C++ Editor
C/C++ Source Open Type Ctrl+Shift+T C/C++ Editor
C/C++ Source Remove Block Comment Ctrl+Shift+\ C/C++ Editor
C/C++ Source Show outline Ctrl+O C/C++ Editor
C/C++ Source Uncomment Ctrl+\ C/C++ Editor
Makefile Source Comment Ctrl+/ Makefile Editor
Makefile Source Open declaration F3 Makefile Editor
Makefile Source Uncomment Ctrl+\ Makefile Editor
Refactor - C/C++ Redo - Refactoring Alt+Shift+Y C/C++ Editor
Refactor - C/C++ Rename - Refactoring Alt+Shift+R C/C++ Editor
Refactor - C/C++ Undo - Refactoring Alt+Shift+Z C/C++ Editor
View Zoom In Ctrl+= 在窗口中
View Zoom Out Ctrl+- 在窗口中
搜索 工作空間中的聲明 Ctrl+G 在窗口中
搜索 工作空間中的引用 Ctrl+Shift+G 在窗口中
搜索 打開“搜索”對話框 Ctrl+H 在窗口中
搜索 顯示“文件中的出現(xiàn)位置”快速菜單 Ctrl+Shift+U 在窗口中
文件 “新建”菜單 Alt+Shift+N 在窗口中
文件 保存 Ctrl+S 在窗口中
文件 全部保存 Ctrl+Shift+S 在窗口中
文件 全部關(guān)閉 Ctrl+Shift+F4 在窗口中
文件 全部關(guān)閉 Ctrl+Shift+W 在窗口中
文件 關(guān)閉 Ctrl+F4 在窗口中
文件 關(guān)閉 Ctrl+W 在窗口中
文件 刷新 F5 在窗口中
文件 屬性 Alt+Enter 在窗口中
文件 打印 Ctrl+P 在窗口中
文件 新建 Ctrl+N 在窗口中
文件 重命名 F2 在窗口中
文本編輯 上一個詞語 Ctrl+左箭頭 編輯文本
文本編輯 上滾行 Ctrl+向上鍵 編輯文本
文本編輯 下一個詞語 Ctrl+右箭頭 編輯文本
文本編輯 下滾行 Ctrl+向下鍵 編輯文本
文本編輯 全部展開 Ctrl+Numpad_Multiply 編輯文本
文本編輯 切換折疊 Ctrl+Numpad_Divide 編輯文本
文本編輯 刪除上一個詞語 Ctrl+Backspace 編輯文本
文本編輯 刪除下一個詞語 Ctrl+Delete 編輯文本
文本編輯 刪除至行末 Ctrl+Shift+Delete 編輯文本
文本編輯 刪除行 Ctrl+D 編輯文本
文本編輯 在當(dāng)前行上面插入行 Ctrl+Shift+Enter 編輯文本
文本編輯 在當(dāng)前行下面插入行 Shift+Enter 編輯文本
文本編輯 復(fù)制行 Ctrl+Alt+向下鍵 編輯文本
文本編輯 將行上移 Alt+向上鍵 編輯文本
文本編輯 將行下移 Alt+向下鍵 編輯文本
文本編輯 展開 Ctrl+Numpad_Add 編輯文本
文本編輯 折疊 Ctrl+Numpad_Subtract 編輯文本
文本編輯 改寫切換 Insert 編輯文本
文本編輯 更改為大寫 Ctrl+Shift+X 編輯文本
文本編輯 更改為小寫 Ctrl+Shift+Y 編輯文本
文本編輯 選擇上一個詞語 Ctrl+Shift+左箭頭 編輯文本
文本編輯 選擇下一個詞語 Ctrl+Shift+右箭頭 編輯文本
文本編輯 重復(fù)行 Ctrl+Alt+向上鍵 編輯文本
查看 Java 包資源管理器 Alt+Shift+Q,P 在窗口中
查看 Java 聲明 Alt+Shift+Q,D 在窗口中
查看 Java 類型層次結(jié)構(gòu) Alt+Shift+Q,T 在窗口中
查看 Javadoc Alt+Shift+Q,J 在窗口中
查看 變量 Alt+Shift+Q,V 在窗口中
查看 同步 Alt+Shift+Q,Y 在窗口中
查看 備忘單 Alt+Shift+Q,H 在窗口中
查看 控制臺 Alt+Shift+Q,C 在窗口中
查看 搜索 Alt+Shift+Q,S 在窗口中
查看 斷點 Alt+Shift+Q,B 在窗口中
查看 顯示視圖 (查看: 大綱) Alt+Shift+Q,O 在窗口中
查看 顯示視圖 (查看: 問題) Alt+Shift+Q,X 在窗口中
瀏覽 &Quick Cross References Alt+Shift+P 編輯 Java 源代碼
瀏覽 Open AspectJ Type Alt+Shift+A 在窗口中
瀏覽 Open AspectJ Type in Hierarchy Alt+Shift+H 在窗口中
瀏覽 “顯示位置”菜單 Alt+Shift+W 在窗口中
瀏覽 上一個編輯位置 Ctrl+Q 在窗口中
瀏覽 下一頁 Ctrl+. 在窗口中
瀏覽 前一頁 Ctrl+, 在窗口中
瀏覽 前移歷史記錄 Alt+右箭頭 在窗口中
瀏覽 后退歷史記錄 Alt+左箭頭 在窗口中
瀏覽 在層次結(jié)構(gòu)中打開類型 Ctrl+Shift+H 在窗口中
瀏覽 快速大綱 Ctrl+O 編輯 Java 源代碼
瀏覽 快速層次結(jié)構(gòu) Ctrl+T 編輯 Java 源代碼
瀏覽 打開聲明 F3 在窗口中
瀏覽 打開外部 Javadoc Shift+F2 在窗口中
瀏覽 打開類型 Ctrl+Shift+T 在窗口中
瀏覽 打開類型層次結(jié)構(gòu) F4 在窗口中
瀏覽 打開結(jié)構(gòu) Ctrl+F3 編輯 Java 源代碼
瀏覽 打開調(diào)用層次結(jié)構(gòu) Ctrl+Alt+H 在窗口中
瀏覽 打開資源 Ctrl+Shift+R 在窗口中
瀏覽 轉(zhuǎn)至上一個成員 Ctrl+Shift+向上鍵 編輯 Java 源代碼
瀏覽 轉(zhuǎn)至下一個成員 Ctrl+Shift+向下鍵 編輯 Java 源代碼
瀏覽 轉(zhuǎn)至匹配的方括號 Ctrl+Shift+P 編輯 Java 源代碼
瀏覽 轉(zhuǎn)至行 Ctrl+L 編輯文本
源代碼 切換 Ant 標(biāo)記出現(xiàn) Alt+Shift+O 編輯 Ant 構(gòu)建文件
源代碼 切換標(biāo)記出現(xiàn) Alt+Shift+O 編輯 Java 源代碼
源代碼 切換注釋 Ctrl+/ 編輯 Java 源代碼
源代碼 切換注釋 Ctrl+7 編輯 Java 源代碼
源代碼 切換注釋 Ctrl+Shift+C 編輯 Java 源代碼
源代碼 在文件中重命名 Alt+Shift+R 編輯 Ant 構(gòu)建文件
源代碼 快速輔助 - 在文件中重命名 Ctrl+2,R 編輯 Java 源代碼
源代碼 快速輔助 - 指定給字段 Ctrl+2,F(xiàn) 編輯 Java 源代碼
源代碼 快速輔助 - 指定給局部變量 Ctrl+2,L 編輯 Java 源代碼
源代碼 打開外部文檔 Shift+F2 編輯 Ant 構(gòu)建文件
源代碼 顯示工具提示描述 F2 編輯 Ant 構(gòu)建文件
源代碼 顯示源代碼快速菜單 Alt+Shift+S 在窗口中
源代碼 格式 Ctrl+Shift+F 編輯 Ant 構(gòu)建文件
源代碼 格式化 Ctrl+Shift+F 編輯 Java 源代碼
源代碼 添加 Javadoc 注釋 Alt+Shift+J 在窗口中
源代碼 添加塊注釋 Ctrl+Shift+/ 編輯 Java 源代碼
源代碼 添加導(dǎo)入 Ctrl+Shift+M 編輯 Java 源代碼
源代碼 組織導(dǎo)入 Ctrl+Shift+O 在窗口中
源代碼 縮進行 Ctrl+I 編輯 Java 源代碼
源代碼 除去出現(xiàn)注釋 Alt+Shift+U 編輯 Java 源代碼
源代碼 除去塊注釋 Ctrl+Shift+\ 編輯 Java 源代碼
窗口 上一個編輯器 Ctrl+Shift+F6 在窗口中
窗口 上一個視圖 Ctrl+Shift+F7 在窗口中
窗口 上一個透視圖 Ctrl+Shift+F8 在窗口中
窗口 下一個編輯器 Ctrl+F6 在窗口中
窗口 下一個視圖 Ctrl+F7 在窗口中
窗口 下一個透視圖 Ctrl+F8 在窗口中
窗口 切換至編輯器 Ctrl+Shift+E 在窗口中
窗口 將活動視圖或編輯器最大化 Ctrl+M 在窗口中
窗口 打開編輯器下拉列表 Ctrl+E 在窗口中
窗口 顯示標(biāo)尺上下文菜單 Ctrl+F10 編輯文本
窗口 顯示系統(tǒng)菜單 Alt+- 在窗口中
窗口 顯示視圖菜單 Ctrl+F10 在窗口中
窗口 顯示鍵輔助 Ctrl+Shift+L 在對話框和窗口中
窗口 激活編輯器 F12 在窗口中
編輯 Add Block Comment Ctrl+Shift+/ Editing in Structured Text Editors
編輯 Format Active Elements Ctrl+I Editing in Structured Text Editors
編輯 Format Document Ctrl+Shift+F Editing in Structured Text Editors
編輯 Move Alt+Shift+V Editing JSP Source
編輯 Occurrences in File Ctrl+Shift+A Editing in Structured Text Editors
編輯 Open Selection F3 Editing in Structured Text Editors
編輯 Quick Fix Ctrl+1 Editing in Structured Text Editors
編輯 Remove Block Comment Ctrl+Shift+\ Editing in Structured Text Editors
編輯 Rename Alt+Shift+R Editing JSP Source
編輯 Rename XSD element Alt+Shift+R Editing XSD context
編輯 Restore Last Selection Alt+Shift+向下鍵 Editing in Structured Text Editors
編輯 Select Enclosing Element Alt+Shift+向上鍵 Editing in Structured Text Editors
編輯 Select Next Element Alt+Shift+右箭頭 Editing in Structured Text Editors
編輯 Select Previous Element Alt+Shift+左箭頭 Editing in Structured Text Editors
編輯 Show Tooltip Description F2 Editing in Structured Text Editors
編輯 Toggle Comment Ctrl+Shift+C Editing in Structured Text Editors
編輯 “快速差別”開關(guān) Ctrl+Shift+Q 編輯文本
編輯 上下文信息 Alt+? 在窗口中
編輯 上下文信息 Alt+Shift+? 在窗口中
編輯 內(nèi)容輔助 Alt+/ 在對話框和窗口中
編輯 切換插入方式 Ctrl+Shift+Insert 編輯文本
編輯 刪除 Delete 在窗口中
編輯 剪切 Ctrl+X 在對話框和窗口中
編輯 剪切 Shift+Delete 在對話框和窗口中
編輯 增量查找 Ctrl+J 編輯文本
編輯 增量逆向查找 Ctrl+Shift+J 編輯文本
編輯 復(fù)制 Ctrl+C 在對話框和窗口中
編輯 復(fù)制 Ctrl+Insert 在對話框和窗口中
編輯 復(fù)原上一個選擇 Alt+Shift+向下鍵 編輯 Java 源代碼
編輯 快速修正 Ctrl+1 在窗口中
編輯 撤消 Ctrl+Z 在窗口中
編輯 文字補全 Ctrl+Alt+/ 編輯文本
編輯 顯示工具提示描述 F2 編輯 Java 源代碼
編輯 查找上一個 Ctrl+Shift+K 編輯文本
編輯 查找下一個 Ctrl+K 編輯文本
編輯 查找并替換 Ctrl+F 在窗口中
編輯 粘貼 Ctrl+V 在對話框和窗口中
編輯 粘貼 Shift+Insert 在對話框和窗口中
編輯 選擇上一個元素 Alt+Shift+左箭頭 編輯 Java 源代碼
編輯 選擇下一個元素 Alt+Shift+右箭頭 編輯 Java 源代碼
編輯 選擇全部 Ctrl+A 在對話框和窗口中
編輯 選擇外層元素 Alt+Shift+向上鍵 編輯 Java 源代碼
編輯 重做 Ctrl+Y 在窗口中
運行/調(diào)試 Debug AspectJ/Java Application Alt+Shift+D,C 在窗口中
運行/調(diào)試 Debug on Server Alt+Shift+D,R 在窗口中
運行/調(diào)試 EOF Ctrl+Z 在控制臺中
運行/調(diào)試 Profile on Server Alt+Shift+P,R 在窗口中
運行/調(diào)試 Run AspectJ/Java Application Alt+Shift+X,C 在窗口中
運行/調(diào)試 Run on Server Alt+Shift+X,R 在窗口中
運行/調(diào)試 切換單步執(zhí)行過濾器 Shift+F5 在窗口中
運行/調(diào)試 切換行斷點 Ctrl+Shift+B 在窗口中
運行/調(diào)試 單步跳入 F5 調(diào)試
運行/調(diào)試 單步跳入選擇的內(nèi)容 Ctrl+F5 調(diào)試
運行/調(diào)試 單步跳過 F6 調(diào)試
運行/調(diào)試 單步返回 F7 調(diào)試
運行/調(diào)試 執(zhí)行 Ctrl+U 在窗口中
運行/調(diào)試 顯示 Ctrl+Shift+D 在對話框和窗口中
運行/調(diào)試 檢查 Ctrl+Shift+I 在對話框和窗口中
運行/調(diào)試 繼續(xù) F8 調(diào)試
運行/調(diào)試 調(diào)試 Ant 構(gòu)建 Alt+Shift+D,Q 在窗口中
運行/調(diào)試 調(diào)試 Eclipse 應(yīng)用程序 Alt+Shift+D,E 在窗口中
運行/調(diào)試 調(diào)試 JUnit 插件測試 Alt+Shift+D,P 在窗口中
運行/調(diào)試 調(diào)試 JUnit 測試 Alt+Shift+D,T 在窗口中
運行/調(diào)試 調(diào)試 Java Applet Alt+Shift+D,A 在窗口中
運行/調(diào)試 調(diào)試 Java 應(yīng)用程序 Alt+Shift+D,J 在窗口中
運行/調(diào)試 調(diào)試 SWT 應(yīng)用程序 Alt+Shift+D,S 在窗口中
運行/調(diào)試 調(diào)試上次啟動 F11 在窗口中
運行/調(diào)試 運行 Ant 構(gòu)建 Alt+Shift+X,Q 在窗口中
運行/調(diào)試 運行 Eclipse 應(yīng)用程序 Alt+Shift+X,E 在窗口中
運行/調(diào)試 運行 JUnit 插件測試 Alt+Shift+X,P 在窗口中
運行/調(diào)試 運行 JUnit 測試 Alt+Shift+X,T 在窗口中
運行/調(diào)試 運行 Java Applet Alt+Shift+X,A 在窗口中
運行/調(diào)試 運行 Java 應(yīng)用程序 Alt+Shift+X,J 在窗口中
運行/調(diào)試 運行 SWT 應(yīng)用程序 Alt+Shift+X,S 在窗口中
運行/調(diào)試 運行上次啟動 Ctrl+F11 在窗口中
運行/調(diào)試 運行至行 Ctrl+R 調(diào)試
重構(gòu) - Java 內(nèi)聯(lián) Alt+Shift+I 在窗口中
重構(gòu) - Java 將局部變量轉(zhuǎn)換為字段 Alt+Shift+F 編輯 Java 源代碼
重構(gòu) - Java 抽取局部變量 Alt+Shift+L 在窗口中
重構(gòu) - Java 抽取方法 Alt+Shift+M 在窗口中
重構(gòu) - Java 撤銷 - 重構(gòu) Alt+Shift+Z 在窗口中
重構(gòu) - Java 顯示重構(gòu)快速菜單 Alt+Shift+T 在窗口中
重構(gòu) - Java 更改方法特征符 Alt+Shift+C 在窗口中
重構(gòu) - Java 移動 - 重構(gòu) Alt+Shift+V 在窗口中
重構(gòu) - Java 重做 - 重構(gòu) Alt+Shift+Y 在窗口中
重構(gòu) - Java 重命名 - 重構(gòu) Alt+Shift+R 在窗口中
項目 全部構(gòu)建 Ctrl+B 在窗口中
posted @
2006-04-05 13:33 阿成 閱讀(223) |
評論 (0) |
編輯 收藏
Spring學(xué)習(xí)筆記(一)依賴注入
?
依賴注入——是Spring最靈魂的設(shè)計思想,有人也叫做控制反轉(zhuǎn)。
1、不管是依賴注入(DI:Dependency Injection)還是控制反轉(zhuǎn)(IoC:Inversion of Control)它的思想是:控制權(quán)由應(yīng)用代碼中轉(zhuǎn)到了外部
容器,即組件之間的依賴關(guān)系由容器在運行期決定,形象的來說,即由容器動態(tài)的將某種依賴關(guān)系注入到組件之中。
2、依賴注入的目標(biāo)并非為軟件系統(tǒng)帶來更多的功能,而是為了提升組件重用的概率,帶來靈活性。
3、舉個例子來說明這個問題。
我曾看到夏昕的《Spring 開發(fā)指南》,上面為說明這個思想,舉了電腦、USB硬盤和U盤的例子,感覺還是不太貼切,今天想了個自認(rèn)為比較好
理解的例子:
有兩種變形金剛的玩具,
一種是固定的,我把它比作原來那種控制權(quán)由應(yīng)用代碼寫死的程序
一種可以拆開重新裝配的,我把它比作用了依賴注入設(shè)計思想的程序
變形金剛的各個部件就象程序的各個組件。
變形金剛的廠家,相對它來說是內(nèi)部的。就象程序的代碼
變形金剛的玩家,相對它來說是外部的。就象程序的容器
大家試想一下,固定變形金剛的控制權(quán)是不是廠家決定的,外部無能為力
而可拆卸的變形金剛的控制權(quán)轉(zhuǎn)移到了外部的玩家,玩家在玩之前可以重新決定各個組件的連接關(guān)系
而這種組件的連接圖是不是也很像依賴注入思想里的配置文件。
大家再從這個例子分析一下依賴注入的目標(biāo)。
posted @
2006-03-23 13:46 阿成 閱讀(311) |
評論 (0) |
編輯 收藏
Spring使用BeanFactory模式來管理Bean,但Spring中提到的Bean不是標(biāo)準(zhǔn)的意義上的JavaBean(僅包含一個默認(rèn)的構(gòu)造函數(shù),在屬性后面定義相對應(yīng)的setter和getter方法),而是任何你想讓它管理的類,比如連接池、甚至BeanFactory本身。
一)Bean的設(shè)計常用下面幾種模式
1、標(biāo)準(zhǔn)Bean:
使用默認(rèn)的構(gòu)造函數(shù)和基于setter、getter方法的依賴注射
Bean類代碼:
java代碼:?
|
public
class ExampleBean { ? ? private BeanOne beanOne; ? ? private BeanTwo beanTwo; ? ? privateint count; ? ? ? ? publicvoid setBeanOne(BeanOne beanOne){ ? ? ? ? this.beanOne = beanOne; ? ? } ? ? ? ? publicvoid setBeanTwo(BeanTwo beanTwo){ ? ? ? ? this.beanTwo = beanTwo; ? ? } ? ? ? ? publicvoid setCount(int count){ ? ? ? ? this.count = count; ? ? }? ? }
|
在配置文件中定義:
java代碼:?
|
<bean id="exampleBean" class="examples.ExampleBean"> ? ? <property name="beanOne"><ref bean="bean1"/></property> ? ? <property name="beanTwo"><ref bean="bean2"/></property> ? ? <property name="count"><value>1</value></property> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
2、構(gòu)造函數(shù)模式
自定義的構(gòu)造函數(shù),基于構(gòu)造函數(shù)參數(shù)的依賴注射
Bean類代碼:
java代碼:?
|
public
class ExampleBean { ? ? private BeanOne beanOne; ? ? private BeanTwo beanTwo; ? ? privateint count; ? ? ? ? public ExampleBean(BeanOne beanOne, BeanTwo beanTwo, int count){ ? ? ? ? this.beanOne = beanOne; ? ? ? ? this.beanTwo = beanTwo; ? ? ? ? this.count = count; ? ? } }
|
在配置文件中定義:
java代碼:?
|
<bean id="exampleBean" class="examples.ExampleBean"> ? ? <constructor-arg><ref bean="bean1"/></constructor-arg> ? ? <constructor-arg><ref bean="bean2"/></constructor-arg> ? ? <constructor-arg><value>1</value></constructor-arg> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
3、靜態(tài)工廠方法模式
靜態(tài)工廠方法必須是static的,基于方法參數(shù)的依賴注射。
Bean類代碼:
java代碼:?
|
public
class ExampleBean { ? ? private BeanOne beanOne; ? ? private BeanTwo beanTwo; ? ? privateint count; ? ? //構(gòu)造函數(shù)私有 ? ? private ExampleBean(BeanOne beanOne, BeanTwo beanTwo, int count){ ? ? ? ? this.beanOne = beanOne; ? ? ? ? this.beanTwo = beanTwo; ? ? ? ? this.count = count; ? ? } ? ? //對外提供靜態(tài)的方法 ? ? publicstatic ExampleBean createInstance(BeanOne beanOne, BeanTwo beanTwo, int count){ ? ? ? ? ExampleBean eb = new ExampleBean(beanOne,beanTwo,count); ? ? ? ? return eb; ? ? } }
|
在配置文件中定義:
java代碼:?
|
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance"> ? ? <constructor-arg><ref bean="bean1"/></constructor-arg> ? ? <constructor-arg><ref bean="bean2"/></constructor-arg> ? ? <constructor-arg><value>1</value></constructor-arg> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
3、實例工廠方法模式
調(diào)用一個已存在的bean(這個bean應(yīng)該是工廠類型)的工廠方法來創(chuàng)建新的bean,基于方法參數(shù)的依賴注射
該模式?jīng)]有Bean類;
在配置文件中定義:
java代碼:?
|
<bean id="exampleBean" ? ? ? factory-bean="myFactoryBean" ? ? ? factory-method="createInstance"/>
<bean id="myFactoryBean" class="examples.ExampleBean" factory-method="createInstance"> ? ? <constructor-arg><ref bean="bean1"/></constructor-arg> ? ? <constructor-arg><ref bean="bean2"/></constructor-arg> ? ? <constructor-arg><value>1</value></constructor-arg> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
二)Bean其它參數(shù)的配置
一個常用Bean的配置參數(shù)和解釋
<bean id="" ——標(biāo)志符,用它引用唯一的Bean
class="" ——該Bean對應(yīng)的類,前面說到實例工廠方法模式創(chuàng)建的Bean沒有類
singleton="" ——值為true或false,標(biāo)識該Bean是否為單實例模式?如果為false則對這個bean
的每次請求都會創(chuàng)建一個新的bean實例
init-method="" ——向應(yīng)用層返回引用前執(zhí)行的初始化方法
destroy-method="" ——該Bean的銷毀方法
depends-on=""> ——在Bean加載前,首先加載的指定資源
....
</bean>
三)property(或constructor-arg元素)的配置
1、用字符串形式指定常見類型的屬性或參數(shù)的value值,JavaBean的PropertyEditor負(fù)責(zé)類型轉(zhuǎn)化如:
java代碼:?
|
<property name="driverClassName"> ? ? <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> ? ? <value>jdbc:mysql://localhost:3306/mydb</value> </property>
|
2、注意null和""(空串)的區(qū)別,如:
java代碼:?
|
<property name="email"><value></value></property> <property name="email"><null/></property>
|
3、list、set、map、以及 props 元素用來定義和設(shè)置Java對應(yīng)類型List、Set、Map、和 Properties ,如:
java代碼:?
|
<property name="school"> ? ?<props> ? ? ? <prop key="school01">The xi'an technology university</prop> ? ? ? <prop key="school02">The BeiJing university</prop> ? ?</props> </property>
<property name="someList"> ? ?<list> ? ? ? <value>a list element followed by a reference</value> ? ? ? <ref bean="myDataSource"/> ? ?</list> </property>
<property name="someMap"> ? ?<map> ? ? ? <entry key="001"> ? ? ? ? ?<value>just some string</value> ? ? ? </entry> ? ? ? <entry key="yup a ref"> ? ? ? ? ?<ref bean="myDataSource"/> ? ? ? </entry> ? ?</map> </property> ? ? ? ? <property name="someSet"> ? ? ? <set> ? ? ? ? ?<value>just some string</value> ? ? ? ? ?<ref bean="myDataSource"/> ? ? ? </set> </property>
|
4、內(nèi)部Bean和ref元素引用容器管理的其他bean
一個內(nèi)部Bean的例子:
java代碼:?
|
<bean id="dep" class="com.bean.Conpany"> ? ? <property name="manager"> ? ? ? ? <bean class="com.bean.Person"> ? ? ? ? ? ? <property name="name"><value>Tony</value></property> ? ? ? ? ? ? <property name="age"><value>51</value></property> ? ? ? ? </bean> ? ? </property> </bean>
|
ref元素引用的例子:
java代碼:?
|
<bean id="person_manger" class="com.bean.Person"> ? ? <property name="name"><value>Tony</value></property> ? ? <property name="age"><value>51</value></property> </bean>
<bean id="dep" class="com.bean.Conpany"> ? ? <property name="manager"> ? ? ? ? <idref bean="person_manager"/> ? ? </property> </bean>
|
注:元素引用可以是下面三種權(quán)限:
1)<idref bean="person_manager"/>
引用的Bean可以在同一個BeanFactory/ApplicationContext(無論是否在同一個XML文件中)中,也可以在父BeanFactory/ApplicationContext中
2)<idref local="person_manager"/>
引用的bean在同一個XML文件中
3)<idref parent="person_manager"/>
引用的bean必須在當(dāng)前BeanFactory(ApplicationContext)的父BeanFactory(ApplicationContext)中.
時間: 2006-3-23 12:58:26?? ?標(biāo)題: Spring學(xué)習(xí)筆記(二)Bean |   |
|
Spring使用BeanFactory模式來管理Bean,但Spring中提到的Bean不是標(biāo)準(zhǔn)的意義上的JavaBean(僅包含一個默認(rèn)的構(gòu)造函數(shù),在屬性后面定義相對應(yīng)的setter和getter方法),而是任何你想讓它管理的類,比如連接池、甚至BeanFactory本身。
一)Bean的設(shè)計常用下面幾種模式
1、標(biāo)準(zhǔn)Bean:
使用默認(rèn)的構(gòu)造函數(shù)和基于setter、getter方法的依賴注射
Bean類代碼:
java代碼:? | publicclass ExampleBean { ? ? private BeanOne beanOne; ? ? private BeanTwo beanTwo; ? ? privateint count; ? ? ? ? publicvoid setBeanOne(BeanOne beanOne){ ? ? ? ? this.beanOne = beanOne; ? ? } ? ? ? ? publicvoid setBeanTwo(BeanTwo beanTwo){ ? ? ? ? this.beanTwo = beanTwo; ? ? } ? ? ? ? publicvoid setCount(int count){ ? ? ? ? this.count = count; ? ? }? ? }
|
在配置文件中定義:
java代碼:? | <bean id="exampleBean" class="examples.ExampleBean"> ? ? <property name="beanOne"><ref bean="bean1"/></property> ? ? <property name="beanTwo"><ref bean="bean2"/></property> ? ? <property name="count"><value>1</value></property> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
2、構(gòu)造函數(shù)模式
自定義的構(gòu)造函數(shù),基于構(gòu)造函數(shù)參數(shù)的依賴注射
Bean類代碼:
java代碼:? | publicclass ExampleBean { ? ? private BeanOne beanOne; ? ? private BeanTwo beanTwo; ? ? privateint count; ? ? ? ? public ExampleBean(BeanOne beanOne, BeanTwo beanTwo, int count){ ? ? ? ? this.beanOne = beanOne; ? ? ? ? this.beanTwo = beanTwo; ? ? ? ? this.count = count; ? ? } }
|
在配置文件中定義:
java代碼:? |
<bean id="exampleBean" class="examples.ExampleBean"> ? ? <constructor-arg><ref bean="bean1"/></constructor-arg> ? ? <constructor-arg><ref bean="bean2"/></constructor-arg> ? ? <constructor-arg><value>1</value></constructor-arg> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
3、靜態(tài)工廠方法模式
靜態(tài)工廠方法必須是static的,基于方法參數(shù)的依賴注射。
Bean類代碼:
java代碼:? | publicclass ExampleBean { ? ? private BeanOne beanOne; ? ? private BeanTwo beanTwo; ? ? privateint count; ? ? //構(gòu)造函數(shù)私有 ? ? private ExampleBean(BeanOne beanOne, BeanTwo beanTwo, int count){ ? ? ? ? this.beanOne = beanOne; ? ? ? ? this.beanTwo = beanTwo; ? ? ? ? this.count = count; ? ? } ? ? //對外提供靜態(tài)的方法 ? ? publicstatic ExampleBean createInstance(BeanOne beanOne, BeanTwo beanTwo, int count){ ? ? ? ? ExampleBean eb = new ExampleBean(beanOne,beanTwo,count); ? ? ? ? return eb; ? ? } }
|
在配置文件中定義:
java代碼:? | <bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance"> ? ? <constructor-arg><ref bean="bean1"/></constructor-arg> ? ? <constructor-arg><ref bean="bean2"/></constructor-arg> ? ? <constructor-arg><value>1</value></constructor-arg> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
3、實例工廠方法模式
調(diào)用一個已存在的bean(這個bean應(yīng)該是工廠類型)的工廠方法來創(chuàng)建新的bean,基于方法參數(shù)的依賴注射
該模式?jīng)]有Bean類;
在配置文件中定義:
java代碼:? | <bean id="exampleBean" ? ? ? factory-bean="myFactoryBean" ? ? ? factory-method="createInstance"/>
<bean id="myFactoryBean" class="examples.ExampleBean" factory-method="createInstance"> ? ? <constructor-arg><ref bean="bean1"/></constructor-arg> ? ? <constructor-arg><ref bean="bean2"/></constructor-arg> ? ? <constructor-arg><value>1</value></constructor-arg> </bean>
<bean id="bean1" class="examples.BeanOne"/> <bean id="bean2" class="examples.BeanTwo"/>
|
二)Bean其它參數(shù)的配置
一個常用Bean的配置參數(shù)和解釋
<bean id="" ——標(biāo)志符,用它引用唯一的Bean class="" ——該Bean對應(yīng)的類,前面說到實例工廠方法模式創(chuàng)建的Bean沒有類 singleton="" ——值為true或false,標(biāo)識該Bean是否為單實例模式?如果為false則對這個bean 的每次請求都會創(chuàng)建一個新的bean實例 init-method="" ——向應(yīng)用層返回引用前執(zhí)行的初始化方法 destroy-method="" ——該Bean的銷毀方法 depends-on=""> ——在Bean加載前,首先加載的指定資源 .... </bean>
三)property(或constructor-arg元素)的配置
1、用字符串形式指定常見類型的屬性或參數(shù)的value值,JavaBean的PropertyEditor負(fù)責(zé)類型轉(zhuǎn)化如:
java代碼:? | <property name="driverClassName"> ? ? <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> ? ? <value>jdbc:mysql://localhost:3306/mydb</value> </property>
|
2、注意null和""(空串)的區(qū)別,如:
java代碼:? |
<property name="email"><value></value></property> <property name="email"><null/></property>
|
3、list、set、map、以及 props 元素用來定義和設(shè)置Java對應(yīng)類型List、Set、Map、和 Properties ,如:
java代碼:? |
<property name="school"> ? ?<props> ? ? ? <prop key="school01">The xi'an technology university</prop> ? ? ? <prop key="school02">The BeiJing university</prop> ? ?</props> </property>
<property name="someList"> ? ?<list> ? ? ? <value>a list element followed by a reference</value> ? ? ? <ref bean="myDataSource"/> ? ?</list> </property>
<property name="someMap"> ? ?<map> ? ? ? <entry key="001"> ? ? ? ? ?<value>just some string</value> ? ? ? </entry> ? ? ? <entry key="yup a ref"> ? ? ? ? ?<ref bean="myDataSource"/> ? ? ? </entry> ? ?</map> </property> ? ? ? ? <property name="someSet"> ? ? ? <set> ? ? ? ? ?<value>just some string</value> ? ? ? ? ?<ref bean="myDataSource"/> ? ? ? </set> </property>
|
|
4、內(nèi)部Bean和ref元素引用容器管理的其他bean
一個內(nèi)部Bean的例子:
java代碼:?
|
<bean id="dep" class="com.bean.Conpany"> ? ? <property name="manager"> ? ? ? ? <bean class="com.bean.Person"> ? ? ? ? ? ? <property name="name"><value>Tony</value></property> ? ? ? ? ? ? <property name="age"><value>51</value></property> ? ? ? ? </bean> ? ? </property> </bean>
|
ref元素引用的例子:
java代碼:?
|
<bean id="person_manger" class="com.bean.Person"> ? ? <property name="name"><value>Tony</value></property> ? ? <property name="age"><value>51</value></property> </bean>
<bean id="dep" class="com.bean.Conpany"> ? ? <property name="manager"> ? ? ? ? <idref bean="person_manager"/> ? ? </property> </bean>
|
注:元素引用可以是下面三種權(quán)限:
1)<idref bean="person_manager"/>
引用的Bean可以在同一個BeanFactory/ApplicationContext(無論是否在同一個XML文件中)中,也可以在父BeanFactory/ApplicationContext中
2)<idref local="person_manager"/>
引用的bean在同一個XML文件中
3)<idref parent="person_manager"/>
引用的bean必須在當(dāng)前BeanFactory(ApplicationContext)的父BeanFactory(ApplicationContext)中
引用注明出處:http://spaces.msn.com/pococoon/blog/cns!D25B6032F7AD1992!193.entry
posted @
2006-03-23 13:42 阿成 閱讀(299) |
評論 (0) |
編輯 收藏
Hibernate一共包括了23個jar包,令人眼花繚亂。本文將詳細(xì)講解Hibernate每個jar包的作用,便于你在應(yīng)用中根據(jù)自己的需要進行取舍。
下載Hibernate,例如2.0.3穩(wěn)定版本,解壓縮,可以看到一個hibernate2.jar和lib目錄下有22個jar包:
hibernate2.jar:
Hibernate的庫,沒有什么可說的,必須使用的jar包
cglib-asm.jar:
CGLIB庫,Hibernate用它來實現(xiàn)PO字節(jié)碼的動態(tài)生成,非常核心的庫,必須使用的jar包
dom4j.jar:
dom4j是一個Java的XML API,類似于jdom,用來讀寫XML文件的。dom4j是一個非常非常優(yōu)秀的Java XML API,具有性能優(yōu)異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件,可以在SourceForge上找到它。在IBM developerWorks上面可以找到一篇文章,對主流的Java XML API進行的性能、功能和易用性的評測,dom4j無論在那個方面都是非常出色的。我早在將近兩年之前就開始使用dom4j,直到現(xiàn)在。如今你可以看到越來越多的Java軟件都在使用dom4j來讀寫XML,特別值得一提的是連Sun的JAXM也在用dom4j。這是必須使用的jar包,Hibernate用它來讀寫配置文件。
odmg.jar:
ODMG是一個ORM的規(guī)范,Hibernate實現(xiàn)了ODMG規(guī)范,這是一個核心的庫,必須使用的jar包。
commons-collections.jar:
Apache Commons包中的一個,包含了一些Apache開發(fā)的集合類,功能比java.util.*強大。必須使用的jar包。
commons-beanutils.jar:
Apache Commons包中的一個,包含了一些Bean工具類類。必須使用的jar包。
commons-lang.jar:
Apache Commons包中的一個,包含了一些數(shù)據(jù)類型工具類,是java.lang.*的擴展。必須使用的jar包。
commons-logging.jar:
Apache Commons包中的一個,包含了日志功能,必須使用的jar包。這個包本身包含了一個Simple Logger,但是功能很弱。在運行的時候它會先在CLASSPATH找log4j,如果有,就使用log4j,如果沒有,就找JDK1.4帶的java.util.logging,如果也找不到就用Simple Logger。commons-logging.jar的出現(xiàn)是一個歷史的的遺留的遺憾,當(dāng)初Apache極力游說Sun把log4j加入JDK1.4,然而JDK1.4項目小組已經(jīng)接近發(fā)布JDK1.4產(chǎn)品的時間了,因此拒絕了Apache的要求,使用自己的java.util.logging,這個包的功能比log4j差的很遠,性能也一般。后來Apache就開發(fā)出來了commons-logging.jar用來兼容兩個logger。因此用commons-logging.jar寫的log程序,底層的Logger是可以切換的,你可以選擇log4j,java.util.logging或者它自帶的Simple Logger。不過我仍然強烈建議使用log4j,因為log4j性能很高,log輸出信息時間幾乎等于System.out,而處理一條log平均只需要5us。你可以在Hibernate的src目錄下找到Hibernate已經(jīng)為你準(zhǔn)備好了的log4j的配置文件,你只需要到Apache 網(wǎng)站去下載log4j就可以了。commons-logging.jar也是必須的jar包。
使用Hibernate必須的jar包就是以上的這幾個,剩下的都是可選的。
ant.jar:
Ant編譯工具的jar包,用來編譯Hibernate源代碼的。如果你不準(zhǔn)備修改和編譯Hibernate源代碼,那么就沒有什么用,可選的jar包
optional.jar:
Ant的一個輔助包。
c3p0.jar:
C3PO是一個數(shù)據(jù)庫連接池,Hibernate可以配置為使用C3PO連接池。如果你準(zhǔn)備用這個連接池,就需要這個jar包。
proxool.jar:
也是一個連接池,同上。
commons-pool.jar, commons-dbcp.jar:
DBCP數(shù)據(jù)庫連接池,Apache的Jakarta組織開發(fā)的,Tomcat4的連接池也是DBCP。
實際上Hibernate自己也實現(xiàn)了一個非常非常簡單的數(shù)據(jù)庫連接池,加上上面3個,你實際上可以在Hibernate上選擇4種不同的數(shù)據(jù)庫連接池,選擇哪一個看個人的偏好,不過DBCP可能更通用一些。另外強調(diào)一點,如果在EJB中使用Hibernate,一定要用App Server的連接池,不要用以上4種連接池,否則容器管理事務(wù)不起作用。
connector.jar:
JCA 規(guī)范,如果你在App Server上把Hibernate配置為Connector的話,就需要這個jar。不過實際上一般App Server肯定會帶上這個包,所以實際上是多余的包。
jaas.jar:
JAAS是用來進行權(quán)限驗證的,已經(jīng)包含在JDK1.4里面了。所以實際上是多余的包。
jcs.jar:
如果你準(zhǔn)備在Hibernate中使用JCS的話,那么必須包括它,否則就不用。
jdbc2_0-stdext.jar:
JDBC2.0的擴展包,一般來說數(shù)據(jù)庫連接池會用上它。不過App Server都會帶上,所以也是多余的。
jta.jar:
JTA規(guī)范,當(dāng)Hibernate使用JTA的時候需要,不過App Server都會帶上,所以也是多余的。
junit.jar:
Junit包,當(dāng)你運行Hibernate自帶的測試代碼的時候需要,否則就不用。
xalan.jar, xerces.jar, xml-apis.jar:
Xerces是XML解析器,Xalan是格式化器,xml-apis實際上是JAXP。一般App Server都會帶上,JDK1.4也包含了解析器,不過不是Xerces,是Crimson,效率比較差,不過Hibernate用XML只不過是讀取配置文件,性能沒什么緊要的,所以也是多余的。
posted @
2006-03-14 20:42 阿成 閱讀(228) |
評論 (0) |
編輯 收藏
這是好友面試的一道題,其實我知道使用的區(qū)別,StringBuffer必須new出來,StringBuffer的append的效率比string的+=的效率高,
其實發(fā)現(xiàn)還有很大的區(qū)別,看了看以前scjp的考題
public class Test {
?? public static void stringReplace (String text) {
?? text = text.replace('j' , 'i');
?? }
??
?? public static void bufferReplace (StringBuffer text) {
?? text = text.append("C");
?? }
??
??? public static void main (String args[]) {
??? String textString = new String ("java");
??? StringBuffer textBuffer = new StringBuffer ("java");
???
??? stringReplace (textString);
??? bufferReplace (textBuffer);
???
??? System.out.println (textString + textBuffer);
??? }
??? }
答案是 javajavaC
這是Java參數(shù)傳遞(by value)造成的,是不可變的(immutable).,例如 基本類型,String傳值,復(fù)制了值傳遞過去;可變的(Object)傳值,復(fù)制了引用傳遞過去。
而題目中第七行text = text.append (“C”),append方法會改變text中的值
而這個text與main中的textBuffer是指向同一個對象,所以對應(yīng)的輸出是javac。
string的值永遠不會改變!
String a = "a";//假設(shè)a指向地址0x0001,
a = "b";//重新負(fù)值后a指向地址0x0002,但0x0001地址中保存的"a"依舊存在,但已經(jīng)不再是a所指向的。
從表面上看String類型的對象改變了值,但事實是他不能改變值,只能改變指向的地址
StringBuffer則不同,直接改變指向的地址中保留的值
還有
StringBuffer s1 = new StringBuffer("a");
StringBuffer s2 = new StringBuffer("a");
s1.equals(s2)//為什么是false
String s1 = new String("a");
String s2 = new String("a");
s1.equals(s2)//為什么是true
StringBuffer類中沒有重新定義equals這個方法,因此這個方法就來自O(shè)bject類,
而Object類中的equals方法是用來比較地址的,所以等于false.
String類中重新定義了equals這個方法,而且比較的是值,而不是地址。所以會是
true。
對于這樣能不能面試出真正的水平,感到懷疑。
posted @
2006-03-09 21:45 阿成 閱讀(294) |
評論 (0) |
編輯 收藏
這是在網(wǎng)上發(fā)現(xiàn)的一篇關(guān)于Spring AOP編程的教程,讀完這篇文章后,Spring AOP不再難以理解,因此我把它譯成中文,推薦給Spring AOP的初學(xué)者。這是譯文的
鏈接
。
AOP正在成為軟件開發(fā)的下一個圣杯。使用AOP,你可以將處理aspect的代碼注入主程序,通常主程序的主要目的并不在于處理這些aspect。AOP可以防止代碼混亂。
為了理解AOP如何做到這點,考慮一下記日志的工作。日志本身不太可能是你開發(fā)的主程序的主要任務(wù)。如果能將“不可見的”、通用的日志代碼注入主程序中,那該多好啊。AOP可以幫助你做到。
Spring framework是很有前途的AOP技術(shù)。作為一種非侵略性的,輕型的AOP framework,你無需使用預(yù)編譯器或其他的元標(biāo)簽,便可以在Java程序中使用它。這意味著開發(fā)團隊里只需一人要對付AOP framework,其他人還是象往常一樣編程。
AOP是很多直覺難以理解的術(shù)語的根源。幸運的是,你只要理解三個概念,就可以編寫AOP模塊。這三個概念是:advice,pointcut和advisor。advice是你想向別的程序內(nèi)部不同的地方注入的代碼。pointcut定義了需要注入advice的位置,通常是某個特定的類的一個public方法。advisor是pointcut和advice的裝配器,是將advice注入主程序中預(yù)定義位置的代碼。
既然我們知道了需要使用advisor向主要代碼中注入“不可見的”advice,讓我們實現(xiàn)一個Spring AOP的例子。在這個例子中,我們將實現(xiàn)一個before advice,這意味著advice的代碼在被調(diào)用的public方法開始前被執(zhí)行。以下是這個before advice的實現(xiàn)代碼:
代碼:
|
package com.company.springaop.test;
import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice;
public class TestBeforeAdvice implements MethodBeforeAdvice {
? public void before(Method m, Object[] args, Object target) ? throws Throwable { ? ? System.out.println("Hello world! (by " ? ? ? ? + this.getClass().getName() ? ? ? ? + ")"); ? } } ? |
接口MethodBeforeAdvice只有一個方法before需要實現(xiàn),它定義了advice的實現(xiàn)。before方法共用三個參數(shù),它們提供了相當(dāng)豐富的信息。參數(shù)Method m是advice開始后執(zhí)行的方法。方法名稱可以用作判斷是否執(zhí)行代碼的條件。Object[] args是傳給被調(diào)用的public方法的參數(shù)數(shù)組。當(dāng)需要記日志時,參數(shù)args和被執(zhí)行方法的名稱,都是非常有用的信息。你也可以改變傳給m的參數(shù),但要小心使用這個功能;編寫最初主程序的程序員并不知道主程序可能會和傳入?yún)?shù)的發(fā)生沖突。Object target是執(zhí)行方法m對象的引用。
在下面的BeanImpl類中,每個public方法調(diào)用前,都會執(zhí)行advice:
代碼:
|
package com.company.springaop.test;
public class BeanImpl implements Bean {
? public void theMethod() { ? ? System.out.println(this.getClass().getName() ? ? ? ? + "." + new Exception().getStackTrace()[0].getMethodName() ? ? ? ? + "()" ? ? ? ? + " says HELLO!"); ? } } |
類BeanImpl實現(xiàn)了下面的接口Bean:
代碼:
|
package com.company.springaop.test;
public interface Bean { ? public void theMethod(); } |
雖然不是必須使用接口,但面向接口而不是面向?qū)崿F(xiàn)編程是良好的編程實踐,Spring也鼓勵這樣做。
pointcut和advice通過配置文件來實現(xiàn),因此,接下來你只需編寫主方法的Java代碼:
代碼:
|
package com.company.springaop.test;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Main {
? public static void main(String[] args) { ? ? //Read the configuration file ? ? ApplicationContext ctx ? ? ? ? = new FileSystemXmlApplicationContext("springconfig.xml");
? ? //Instantiate an object ? ? Bean x = (Bean) ctx.getBean("bean");
? ? //Execute the public method of the bean (the test) ? ? x.theMethod(); ? } } |
我們從讀入和處理配置文件開始,接下來馬上要創(chuàng)建它。這個配置文件將作為粘合程序不同部分的“膠水”。讀入和處理配置文件后,我們會得到一個創(chuàng)建工廠ctx。任何一個Spring管理的對象都必須通過這個工廠來創(chuàng)建。對象通過工廠創(chuàng)建后便可正常使用。
僅僅用配置文件便可把程序的每一部分組裝起來。
代碼:
|
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC? "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> ? <!--CONFIG--> ? <bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean"> ? ? <property name="proxyInterfaces"> ? ? ? <value>com.company.springaop.test.Bean</value> ? ? </property> ? ? <property name="target"> ? ? ? <ref local="beanTarget"/> ? ? </property> ? ? <property name="interceptorNames"> ? ? ? <list> ? ? ? ? <value>theAdvisor</value> ? ? ? </list> ? ? </property> ? </bean>
? <!--CLASS--> ? <bean id="beanTarget" class="com.company.springaop.test.BeanImpl"/>
? <!--ADVISOR--> ? <!--Note: An advisor assembles pointcut and advice--> ? <bean id="theAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> ? ? <property name="advice"> ? ? ? <ref local="theBeforeAdvice"/> ? ? </property> ? ? <property name="pattern"> ? ? ? <value>com\.company\.springaop\.test\.Bean\.theMethod</value> ? ? </property> ? </bean>
? <!--ADVICE--> ? <bean id="theBeforeAdvice" class="com.company.springaop.test.TestBeforeAdvice"/> </beans> ? |
四個bean定義的次序并不重要。我們現(xiàn)在有了一個advice,一個包含了正則表達式pointcut的advisor,一個主程序類和一個配置好的接口,通過工廠ctx,這個接口返回自己本身實現(xiàn)的一個引用。
BeanImpl和TestBeforeAdvice都是直接配置。我們用一個唯一的ID創(chuàng)建一個bean元素,并指定了一個實現(xiàn)類。這就是全部的工作。
advisor通過Spring framework提供的一個RegexMethodPointcutAdvisor類來實現(xiàn)。我們用advisor的一個屬性來指定它所需的advice-bean。第二個屬性則用正則表達式定義了pointcut,確保良好的性能和易讀性。
最后配置的是bean,它可以通過一個工廠來創(chuàng)建。bean的定義看起來比實際上要復(fù)雜。bean是ProxyFactoryBean的一個實現(xiàn),它是Spring framework的一部分。這個bean的行為通過一下的三個屬性來定義:
- 屬性proxyInterface定義了接口類。
- 屬性target指向本地配置的一個bean,這個bean返回一個接口的實現(xiàn)。
- 屬性interceptorNames是唯一允許定義一個值列表的屬性。這個列表包含所有需要在beanTarget上執(zhí)行的advisor。注意,advisor列表的次序是非常重要的。
Spring工具
雖然你可以手工修改Ant構(gòu)建腳本,但使用SpringUI(譯注:SpringUI現(xiàn)在是Spring framework的一部分,并改名為spring-ide),使用Spring AOP變得很簡單,只要點點鼠標(biāo)即可。你可以把SpringUI安裝成Eclipse的一個plug-in。然后,你只需在你的project上右擊鼠標(biāo),并選擇“add Spring Project Nature”。在project屬性中,你可以在“Spring Project”下添加Spring配置文件。在編譯前把下面的類庫加入project:aopalliance.jar,commons-logging.jar,jakarta-oro-2.0.7.jar和spring.jar。運行程序時你會看到下面的信息:
... (logging information)
Hello world! (by com.company.springaop.test.TestBeforeAdvice)
com.company.springaop.test.BeanImpl.theMethod() says HELLO!
優(yōu)點和缺點
Spring比起其他的framework更有優(yōu)勢,因為除了AOP以外,它提供了更多別的功能。作為一個輕型framework,它在J2EE不同的部分都可以發(fā)揮作用。因此,即使不想使用Spring AOP,你可能還是想使用Spring。另一個優(yōu)點是,Spring并不要求開發(fā)團隊所有的人員都會用它。學(xué)習(xí)Spring應(yīng)該從Spring reference的第一頁開始。讀了本文后,你應(yīng)該可以更好地理解Spring reference了。Spring唯一的缺點是缺乏更多的文檔,但它的mailing list是個很好的補充,而且會不斷地出現(xiàn)更多的文檔。
posted @
2006-03-09 21:32 阿成 閱讀(311) |
評論 (0) |
編輯 收藏
很多人對二級緩存都不太了解,或者是有錯誤的認(rèn)識,我一直想寫一篇文章介紹一下hibernate的二級緩存的,今天終于忍不住了。
我的經(jīng)驗主要來自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請原諒我的頑固不化。
hibernate的session提供了一級緩存,每個session,對同一個id進行兩次load,不會發(fā)送兩條sql給數(shù)據(jù)庫,但是session關(guān)閉的時候,一級緩存就失效了。
二級緩存是SessionFactory級別的全局緩存,它底下可以使用不同的緩存類庫,比如ehcache、oscache等,需要設(shè)置hibernate.cache.provider_class,我們這里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查詢緩存,加上
hibernate.cache.use_query_cache=true
緩存可以簡單的看成一個Map,通過key在緩存里面找value。
Class的緩存
對于一條記錄,也就是一個PO來說,是根據(jù)ID來找的,緩存的key就是ID,value是POJO。無論list,load還是iterate,只要讀出一個對象,都會填充緩存。但是list不會使用緩存,而iterate會先取數(shù)據(jù)庫select id出來,然后一個id一個id的load,如果在緩存里面有,就從緩存取,沒有的話就去數(shù)據(jù)庫load。假設(shè)是讀寫緩存,需要設(shè)置:
<cache usage="read-write"/>
如果你使用的二級緩存實現(xiàn)是ehcache的話,需要配置ehcache.xml
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
其中eternal表示緩存是不是永遠不超時,timeToLiveSeconds是緩存中每個元素(這里也就是一個POJO)的超時時間,如果eternal="false",超過指定的時間,這個元素就被移走了。timeToIdleSeconds是發(fā)呆時間,是可選的。當(dāng)往緩存里面put的元素超過500個時,如果overflowToDisk="true",就會把緩存中的部分?jǐn)?shù)據(jù)保存在硬盤上的臨時文件里面。
每個需要緩存的class都要這樣配置。如果你沒有配置,hibernate會在啟動的時候警告你,然后使用defaultCache的配置,這樣多個class會共享一個配置。
當(dāng)某個ID通過hibernate修改時,hibernate會知道,于是移除緩存。
這樣大家可能會想,同樣的查詢條件,第一次先list,第二次再iterate,就可以使用到緩存了。實際上這是很難的,因為你無法判斷什么時候是第一次,而且每次查詢的條件通常是不一樣的,假如數(shù)據(jù)庫里面有100條記錄,id從1到100,第一次list的時候出了前50個id,第二次iterate的時候卻查詢到30至70號id,那么30-50是從緩存里面取的,51到70是從數(shù)據(jù)庫取的,共發(fā)送1+20條sql。所以我一直認(rèn)為iterate沒有什么用,總是會有1+N的問題。
(題外話:有說法說大型查詢用list會把整個結(jié)果集裝入內(nèi)存,很慢,而iterate只select id比較好,但是大型查詢總是要分頁查的,誰也不會真的把整個結(jié)果集裝進來,假如一頁20條的話,iterate共需要執(zhí)行21條語句,list雖然選擇若干字段,比iterate第一條select id語句慢一些,但只有一條語句,不裝入整個結(jié)果集hibernate還會根據(jù)數(shù)據(jù)庫方言做優(yōu)化,比如使用mysql的limit,整體看來應(yīng)該還是list快。)
如果想要對list或者iterate查詢的結(jié)果緩存,就要用到查詢緩存了
查詢緩存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
然后
query.setCacheable(true);//激活查詢緩存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可選
第二行指定要使用的cacheRegion是myCacheRegion,即你可以給每個查詢緩存做一個單獨的配置,使用setCacheRegion來做這個指定,需要在ehcache.xml里面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略第二行,不設(shè)置cacheRegion的話,那么會使用上面提到的標(biāo)準(zhǔn)查詢緩存的配置,也就是net.sf.hibernate.cache.StandardQueryCache
對于查詢緩存來說,緩存的key是根據(jù)hql生成的sql,再加上參數(shù),分頁等信息(可以通過日志輸出看到,不過它的輸出不是很可讀,最好改一下它的代碼)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
參數(shù)是"tiger%",那么查詢緩存的key*大約*是這樣的字符串(我是憑記憶寫的,并不精確,不過看了也該明白了):
select * from cat c where c.name like ? , parameter:tiger%
這樣,保證了同樣的查詢、同樣的參數(shù)等條件下具有一樣的key。
現(xiàn)在說說緩存的value,如果是list方式的話,value在這里并不是整個結(jié)果集,而是查詢出來的這一串ID。也就是說,不管是list方法還是iterate方法,第一次查詢的時候,它們的查詢方式很它們平時的方式是一樣的,list執(zhí)行一條sql,iterate執(zhí)行1+N條,多出來的行為是它們填充了緩存。但是到同樣條件第二次查詢的時候,就都和iterate的行為一樣了,根據(jù)緩存的key去緩存里面查到了value,value是一串id,然后在到class的緩存里面去一個一個的load出來。這樣做是為了節(jié)約內(nèi)存。
可以看出來,查詢緩存需要打開相關(guān)類的class緩存。list和iterate方法第一次執(zhí)行的時候,都是既填充查詢緩存又填充class緩存的。
這里還有一個很容易被忽視的重要問題,即打開查詢緩存以后,即使是list方法也可能遇到1+N的問題!相同條件第一次list的時候,因為查詢緩存中找不到,不管class緩存是否存在數(shù)據(jù),總是發(fā)送一條sql語句到數(shù)據(jù)庫獲取全部數(shù)據(jù),然后填充查詢緩存和class緩存。但是第二次執(zhí)行的時候,問題就來了,如果你的class緩存的超時時間比較短,現(xiàn)在class緩存都超時了,但是查詢緩存還在,那么list方法在獲取id串以后,將會一個一個去數(shù)據(jù)庫load!因此,class緩存的超時時間一定不能短于查詢緩存設(shè)置的超時時間!如果還設(shè)置了發(fā)呆時間的話,保證class緩存的發(fā)呆時間也大于查詢的緩存的生存時間。這里還有其他情況,比如class緩存被程序強制evict了,這種情況就請自己注意了。
另外,如果hql查詢包含select字句,那么查詢緩存里面的value就是整個結(jié)果集了。
當(dāng)hibernate更新數(shù)據(jù)庫的時候,它怎么知道更新哪些查詢緩存呢?
hibernate在一個地方維護每個表的最后更新時間,其實也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置里面。
當(dāng)通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然后它更新這些表的最后更新時間。每個緩存都有一個生成時間和這個緩存所查詢的表,當(dāng)hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然后去查找這些表的最后更新時間,如果有一個表在生成時間后更新過了,那么這個緩存是無效的。
可以看出,只要更新過一個表,那么凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。
Collection緩存
需要在hbm的collection里面設(shè)置
<cache usage="read-write"/>
假如class是Cat,collection叫children,那么ehcache里面配置
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Collection的緩存和前面查詢緩存的list一樣,也是只保持一串id,但它不會因為這個表更新過就失效,一個collection緩存僅在這個collection里面的元素有增刪時才失效。
這樣有一個問題,如果你的collection是根據(jù)某個字段排序的,當(dāng)其中一個元素更新了該字段時,導(dǎo)致順序改變時,collection緩存里面的順序沒有做更新。
緩存策略
只讀緩存(read-only):沒有什么好說的
讀/寫緩存(read-write):程序可能要的更新數(shù)據(jù)
不嚴(yán)格的讀/寫緩存(nonstrict-read-write):需要更新數(shù)據(jù),但是兩個事務(wù)更新同一條記錄的可能性很小,性能比讀寫緩存好
事務(wù)緩存(transactional):緩存支持事務(wù),發(fā)生異常的時候,緩存也能夠回滾,只支持jta環(huán)境,這個我沒有怎么研究過
讀寫緩存和不嚴(yán)格讀寫緩存在實現(xiàn)上的區(qū)別在于,讀寫緩存更新緩存的時候會把緩存里面的數(shù)據(jù)換成一個鎖,其他事務(wù)如果去取相應(yīng)的緩存數(shù)據(jù),發(fā)現(xiàn)被鎖住了,然后就直接取數(shù)據(jù)庫查詢。
在hibernate2.1的ehcache實現(xiàn)中,如果鎖住部分緩存的事務(wù)發(fā)生了異常,那么緩存會一直被鎖住,直到60秒后超時。
不嚴(yán)格讀寫緩存不鎖定緩存中的數(shù)據(jù)。
使用二級緩存的前置條件
你的hibernate程序?qū)?shù)據(jù)庫有獨占的寫訪問權(quán),其他的進程更新了數(shù)據(jù)庫,hibernate是不可能知道的。你操作數(shù)據(jù)庫必需直接通過hibernate,如果你調(diào)用存儲過程,或者自己使用jdbc更新數(shù)據(jù)庫,hibernate也是不知道的。hibernate3.0的大批量更新和刪除是不更新二級緩存的,但是據(jù)說3.1已經(jīng)解決了這個問題。
這個限制相當(dāng)?shù)募郑袝r候hibernate做批量更新、刪除很慢,但是你卻不能自己寫jdbc來優(yōu)化,很郁悶吧。
SessionFactory也提供了移除緩存的方法,你一定要自己寫一些JDBC的話,可以調(diào)用這些方法移除緩存,這些方法是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不過我不建議這樣做,因為這樣很難維護。比如你現(xiàn)在用JDBC批量更新了某個表,有3個查詢緩存會用到這個表,用evictQueries(String cacheRegion)移除了3個查詢緩存,然后用evict(Class persistentClass)移除了class緩存,看上去好像完整了。不過哪天你添加了一個相關(guān)查詢緩存,可能會忘記更新這里的移除代碼。如果你的jdbc代碼到處都是,在你添加一個查詢緩存的時候,還知道其他什么地方也要做相應(yīng)的改動嗎?
----------------------------------------------------
總結(jié):
不要想當(dāng)然的以為緩存一定能提高性能,僅僅在你能夠駕馭它并且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的,不方便用jdbc可能會大大的降低更新性能。在不了解原理的情況下亂用,可能會有1+N的問題。不當(dāng)?shù)氖褂眠€可能導(dǎo)致讀出臟數(shù)據(jù)。
如果受不了hibernate的諸多限制,那么還是自己在應(yīng)用程序的層面上做緩存吧。
在越高的層面上做緩存,效果就會越好。就好像盡管磁盤有緩存,數(shù)據(jù)庫還是要實現(xiàn)自己的緩存,盡管數(shù)據(jù)庫有緩存,咱們的應(yīng)用程序還是要做緩存。因為底層的緩存它并不知道高層要用這些數(shù)據(jù)干什么,只能做的比較通用,而高層可以有針對性的實現(xiàn)緩存,所以在更高的級別上做緩存,效果也要好些吧。
posted @
2006-03-09 20:56 阿成 閱讀(273) |
評論 (0) |
編輯 收藏
前幾天接到了新的任務(wù),開始了公司項目管理軟件的開發(fā)(復(fù)雜其中一部分).
這段時間開始由項目經(jīng)理帶著我們開發(fā),這幾天跟他學(xué)到的東西還是不少的.如果每天都能這樣
該多好呀.?? 而且意識到嚴(yán)謹(jǐn)?shù)?font color="#ff0000">學(xué)習(xí)態(tài)度的重要性,不能囫圇吞棗.要學(xué)就要學(xué)通.
posted @
2006-03-09 20:52 阿成 閱讀(223) |
評論 (0) |
編輯 收藏
轉(zhuǎn)自:Potain 的BLOG
OpenSessionInView
Created by
potian. Last edited by
admin 61 days ago. Viewed 181 times.
[edit]
[attach]
Hibernate的Lazy初始化1:n關(guān)系時,你必須保證是在同一個Session內(nèi)部使用這個關(guān)系集合,不然Hiernate將拋出例外。
另外,你不愿意你的DAO測試代碼每次都打開關(guān)系Session,因此,我們一般會采用OpenSessionInView模式。
OpenSessionInViewFilter解決Web應(yīng)用程序的問題
如果程序是在正常的Web程序中運行,那么Spring的
OpenSessionInViewFilter能夠解決問題,它:
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
?????? FilterChain filterChain) throws ServletException, IOException {
??????SessionFactory sessionFactory = lookupSessionFactory();
??????logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
??????Session session = getSession(sessionFactory);
??????TransactionSynchronizationManager.bindResource(sessionFactory,
new SessionHolder(session));
??????try {
????????????filterChain.doFilter(request, response);
??????}
??????finally {
????????????TransactionSynchronizationManager.unbindResource(sessionFactory);
????????????logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
????????????closeSession(session, sessionFactory);
??????}
}
可以看到,這個Filter在request開始之前,把sessionFactory綁定到TransactionSynchronizationManager,和這個SessionHolder相關(guān)。這個意味著所有request執(zhí)行過程中將使用這個session。而在請求結(jié)束后,將和這個sessionFactory對應(yīng)的session解綁,并且關(guān)閉Session。
為什么綁定以后,就可以防止每次不會新開一個Session呢?看看HibernateDaoSupport的情況:
publicfinal void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
protectedfinal HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
我們的DAO將使用這個template進行操作:
publicabstract class BaseHibernateObjectDao
??????extends HibernateDaoSupport
??????implements BaseObjectDao {
??????protected BaseEntityObject getByClassId(finallong id) {
????????????BaseEntityObject obj =
??????????????????(BaseEntityObject) getHibernateTemplate()
????????????????????????.execute(new HibernateCallback() {
??????????????????publicObject doInHibernate(Session session)
????????????????????????throws HibernateException {
????????????????????????return session.get(getPersistentClass(),
newLong(id));
??????????????????}
????????????});
????????????return obj;
??????}
??????public void save(BaseEntityObject entity) {
????????????getHibernateTemplate().saveOrUpdate(entity);
??????}
??????public void remove(BaseEntityObject entity) {
????????????try {
??????????????????getHibernateTemplate().delete(entity);
????????????} catch (Exception e) {
??????????????????thrownew FlexEnterpriseDataAccessException(e);
????????????}
??????}
??????public void refresh(final BaseEntityObject entity) {
????????????getHibernateTemplate().execute(new HibernateCallback() {
??????????????????publicObject doInHibernate(Session session)
????????????????????????throws HibernateException {
????????????????????????session.refresh(entity);
????????????????????????returnnull;
??????????????????}
????????????});
??????}
??????public void replicate(finalObject entity) {
????????????getHibernateTemplate().execute(new HibernateCallback() {
??????????????????publicObject doInHibernate(Session session)
????????????????????????throws HibernateException {
????????????????????????session.replicate(entity,
ReplicationMode.OVERWRITE);
????????????????????????returnnull;
??????????????????}
????????????});
??????}
而HibernateTemplate試圖每次在execute之前去獲得Session,執(zhí)行完就力爭關(guān)閉Session
publicObject execute(HibernateCallback action) throws DataAccessException {
??????Session session = (!this.allowCreate ?
????????????SessionFactoryUtils.getSession(getSessionFactory(),
false) :
????????????SessionFactoryUtils.getSession(getSessionFactory(),
getEntityInterceptor(),
getJdbcExceptionTranslator()));
??????boolean existingTransaction =
TransactionSynchronizationManager.hasResource(getSessionFactory());
??????if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {
????????????session.setFlushMode(FlushMode.NEVER);
??????}
??????try {
????????????Object result = action.doInHibernate(session);
????????????flushIfNecessary(session, existingTransaction);
????????????return result;
??????}
??????catch (HibernateException ex) {
????????????throw convertHibernateAccessException(ex);
??????}
??????catch (SQLException ex) {
????????????throw convertJdbcAccessException(ex);
??????}
??????catch (RuntimeException ex) {
????????????// callback code threw application exception
????????????throw ex;
??????}
??????finally {
????????????SessionFactoryUtils.closeSessionIfNecessary(
session, getSessionFactory());
??????}
}
而這個SessionFactoryUtils能否得到當(dāng)前的session以及closeSessionIfNecessary是否真正關(guān)閉session,端取決于這個session是否用sessionHolder和這個sessionFactory在我們最開始提到的TransactionSynchronizationManager綁定。
publicstatic void closeSessionIfNecessary(Session session,
SessionFactory sessionFactory)
throws CleanupFailureDataAccessException {
??????if (session == null ||
?????? TransactionSynchronizationManager.hasResource(sessionFactory)) {
????????????return;
??????}
??????logger.debug("Closing Hibernate session");
??????try {
????????????session.close();
??????}
??????catch (JDBCException ex) {
????????????// SQLException underneath
????????????thrownew CleanupFailureDataAccessException(
????????????"Cannot close Hibernate session", ex.getSQLException());
??????}
??????catch (HibernateException ex) {
????????????thrownew CleanupFailureDataAccessException(
????????????"Cannot close Hibernate session", ex);
??????}
}
HibernateInterceptor和OpenSessionInViewInterceptor的問題
使用同樣的方法,這兩個Interceptor可以用來解決問題。但是關(guān)鍵的不同之處在于,它們的力度只能定義在DAO或業(yè)務(wù)方法上,而不是在我們的Test方法上,除非我們把它們應(yīng)用到TestCase的方法上,但你不大可能為TestCase去定義一個接口,然后把Interceptor應(yīng)用到這個接口的某些方法上。直接使用HibernateTransactionManager也是一樣的。因此,如果我們有這樣的測試:
Category parentCategory = new Category ();
??????parentCategory.setName("parent");
??????dao.save(parentCategory);
??????Category childCategory = new Category();
childCategory.setName("child");
??????parentCategory.addChild(childCategory);
??????dao.save(childCategory);
??????Category savedParent = dao.getCategory("parent");
??????Category savedChild = (Category ) savedParent.getChildren().get(0);
??????assertEquals(savedChild, childCategory);
將意味著兩件事情:
- 每次DAO執(zhí)行都會啟動一個session和關(guān)閉一個session
- 如果我們定義了一個lazy的關(guān)系,那么最后的Category savedChild = (Category ) savedParent.getChildren().get(0);將會讓hibernate報錯。
解決方案
一種方法是對TestCase應(yīng)用Interceptor或者TransactionManager,但這個恐怕會造成很多麻煩。除非是使用增強方式的AOP.我前期采用這種方法(Aspectwerkz),在Eclipse里面也跑得含好。
另一種方法是在TestCase的setup和teardown里面實現(xiàn)和Filter完全一樣的處理,其他的TestCase都從這個TestCase繼承,這種方法是我目前所使用的。
轉(zhuǎn)自:Karl Baum's Weblog
Karl Baum's Weblog
All | General | Java
Thursday July 08, 2004
Lazy Initialization and the DAO pattern with Hibernate and Spring
Hibernate and Lazy Initialization
Hibernate object relational mapping offers both lazy and non-lazy modes of object initialization. Non-lazy initialization retrieves an object and all of its related objects at load time. This can result in hundreds if not thousands of select statements when retrieving one entity. The problem is compounded when bi-directional relationships are used, often causing entire databases to be loaded during the initial request. Of course one could tediously examine each object relationship and manually remove those most costly, but in the end, we may be losing the ease of use benefit sought in using the ORM tool.
The obvious solution is to employ the lazy loading mechanism provided by hibernate. This initialization strategy only loads an object's one-to-many and many-to-many relationships when these fields are accessed. The scenario is practically transparent to the developer and a minimum amount of database requests are made, resulting in major performance gains. One drawback to this technique is that lazy loading requires the Hibernate session to remain open while the data object is in use. This causes a major problem when trying to abstract the persistence layer via the Data Access Object pattern. In order to fully abstract the persistence mechanism, all database logic, including opening and closing sessions, must not be performed in the application layer. Most often, this logic is concealed behind the DAO implementation classes which implement interface stubs. The quick and dirty solution is to forget the DAO pattern and include database connection logic in the application layer. This works for small applications but in large systems this can prove to be a major design flaw, hindering application extensibility.
Being Lazy in the Web Layer
Fortunately for us, the Spring Framework has developed an out of box web solution for using the DAO pattern in combination with Hibernate lazy loading. For anyone not familiar with using the Spring Framework in combination with Hibernate, I will not go into the details here, but I encourage you to read Hibernate Data Access with the Spring Framework. In the case of a web application, Spring comes with both the OpenSessionInViewFilter and the OpenSessionInViewInterceptor. One can use either one interchangeably as both serve the same function. The only difference between the two is the interceptor runs within the Spring container and is configured within the web application context while the Filter runs in front of Spring and is configured within the web.xml. Regardless of which one is used, they both open the hibernate session during the request binding this session to the current thread. Once bound to the thread, the open hibernate session can transparently be used within the DAO implementation classes. The session will remain open for the view allowing lazy access the database value objects. Once the view logic is complete, the hibernate session is closed either in the Filter doFilter method or the Interceptor postHandle method. Below is an example of the configuration of each component:
Interceptor Configuration
<beans>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="openSessionInViewInterceptor"/>
</list>
</property>
<property name="mappings">
...
</bean>
...
<bean name="openSessionInViewInterceptor"
class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
</beans>
Filter Configuration
<web-app>
...
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate.support.OpenSessionInViewFilter
</filter-class>
</filter>
...
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.spring</url-pattern>
</filter-mapping>
...
</web-app>
Implementing the Hibernate DAO's to use the open session is simple. In fact, if you are already using the Spring Framework to implement your Hibernate DAO's, most likely you will not have to change a thing. The DAO's must access Hibernate through the convenient HibernateTemplate utility, which makes database access a piece of cake. Below is an example DAO.
Example DAO
public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {
public Product getProduct(Integer productId) {
return (Product)getHibernateTemplate().load(Product.class, productId);
}
public Integer saveProduct(Product product) {
return (Integer) getHibernateTemplate().save(product);
}
public void updateProduct(Product product) {
getHibernateTemplate().update(product);
}
}
Being Lazy in the Business Layer
Even outside the view, the Spring Framework makes it easy to use lazy load initialization, through the AOP interceptor HibernateInterceptor. The hibernate interceptor transparently intercepts calls to any business object configured in the Spring application context, opening a hibernate session before the call, and closing the session afterward. Let's run through a quick example. Suppose we have an interface BusinessObject:
public interface BusinessObject {
public void doSomethingThatInvolvesDaos();
}
The class BusinessObjectImpl implements BusinessObject:
public class BusinessObjectImpl implements BusinessObject {
public void doSomethingThatInvolvesDaos() {
// lots of logic that calls
// DAO classes Which access
// data objects lazily
}
}
Through some configurations in the Spring application context, we can instruct the HibernateInterceptor to intercept calls to the BusinessObjectImpl allowing it's methods to lazily access data objects. Take a look at the fragment below:
<beans>
<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl">
<property name="someDAO"><ref bean="someDAO"/></property>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="businessObjectTarget"/></property>
<property name="proxyInterfaces">
<value>com.acompany.BusinessObject</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>
</beans>
When the businessObject bean is referenced, the HibernateInterceptor opens a hibernate session and passes the call onto the BusinessObjectImpl. When the BusinessObjectImpl has finished executing, the HibernateInterceptor transparently closes the session. The application code has no knowledge of any persistence logic, yet it is still able to lazily access data objects.
Being Lazy in your Unit Tests
Last but not least, we'll need the ability to test our lazy application from J-Unit. This is easily done by overriding the setUp and tearDown methods of the TestCase class. I prefer to keep this code in a convenient abstract TestCase class for all of my tests to extend.
public abstract class MyLazyTestCase extends TestCase {
private SessionFactory sessionFactory;
private Session session;
public void setUp() throws Exception {
super.setUp();
SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
session = SessionFactoryUtils.getSession(sessionFactory, true);
Session s = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));
}
protected Object getBean(String beanName) {
//Code to get objects from Spring application context
}
public void tearDown() throws Exception {
super.tearDown();
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
Session s = holder.getSession();
s.flush();
TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory);
}
}
( Jul 08 2004, 09:39:55 AM EDT ) Permalink Comments [2]
Trackback URL: http://jroller.com/trackback/kbaum/Weblog/orm_lazy_initialization_with_dao
Comments:
A few things to keep in the back of your mind if you take this approach; 1. If any errors occur while attempting to lazy load relationships in the view (JSP) it would be hard to present a nice error to the user. 2. This would result in at least 2 hibernate sessions (db connections being open for any one request), so you might want to up the number of connections available. Cheers, Dan
Posted by Dan Washusen on July 08, 2004 at 09:02 PM EDT #
I am a little confused on why it would be difficult to show a nice error jsp. Couldn't we just use the provided servlet container error page mechanisms? In regards to the 2 hibernate sessions being opened. Are you saying that the OpenSessionInViewInterceptor would be run twice if an exception was thrown? Thanks for your feedback!
posted @
2006-03-09 08:52 阿成 閱讀(1226) |
評論 (0) |
編輯 收藏
1、我認(rèn)為最關(guān)鍵的,是要讓mm看到你的上進心。??
男人的最大魅力在于事業(yè)有成,年輕人工作時間不長談不上“有成”,這時候你就要讓mm覺得你是
????個有上進心的人。??
別的可以胡說八道,但這個問題不能含糊,你一定要告訴mm,你對未來充滿信心,你不滿足于現(xiàn)狀,并且你已經(jīng)有了長遠的計劃,總之你的未來不是夢。??
??
2、要顯得有信心、有責(zé)任心??
不要像個小孩子,女孩子都很懶希望能找個依*,你要拿出自己的信心和責(zé)任心來。??
有一個錯的選擇總比沒有選擇要好的多。??
??
3、不要太正經(jīng),但也不要太隨?nbsp;?
該正經(jīng)的地方就正經(jīng),該調(diào)侃的的時候就調(diào)侃。??
女孩子都喜歡有點玩世不恭的男人,所以別顯得對什么都特別在意,那樣太呆板。??
??
4、顯得成熟一點??
遇事鎮(zhèn)定、從容不迫的男人對mm有致命的吸引力。??
??
二、如何與mm展開進一步接觸(時間:開始追的階段)??
??
1、這個階段最關(guān)鍵的是不能著急,不要把事情弄的那么清楚,讓人家一眼就能看出你在追人家。??
想一想,一般人都不會一眼就看上你,但也不會看一眼就討厭你,都是老百姓家的孩子(除非你長得象周潤發(fā)劉德華或者凱文科斯特納),好感是需要隨著了解的不斷增加而實現(xiàn)的,所以問題的關(guān)鍵是你要得的進一步發(fā)展的機會。??
站在女孩子的角度替人家想一想:你這么直接了當(dāng)?shù)臎_過來要搞對象,女孩子肯定有心理壓力。這要是接觸一陣后發(fā)現(xiàn)不喜歡你,那不就成了耍你了么?所以如果你開始就擺出志在必得的姿勢出來,基本上會被立刻悶回去。??
??
2、要低姿態(tài)起步??
首先要把關(guān)系定位成“朋友”,本來是“普通朋友”,你希望成為“好朋友”,有品位的還可以要求對方成為“紅顏知己”什么的,總之千萬不要說“追你”。??
你想想,你如果根本不提“追”,那么女孩子也就更沒機會“拒絕”你——你沒追她怎么拒絕你?!??
這樣可以減輕女孩子的心理壓力,使你們能順利的交往下去。不要幻想認(rèn)識三天就答應(yīng)嫁給你,要充分的交往、了解,感情不是憑空產(chǎn)生的。??
??
3、交往的過程中不要太急躁??
要有張有弛,不要整天纏著人家,誰這樣對你,你也會膩。我有個好朋友對我說,追女孩子的關(guān)鍵是八個字—— “忽冷忽熱、欲擒故縱”(這是我同學(xué)多少年心血的結(jié)晶)。??
??
你整天纏著人家自然不覺得你好,你適當(dāng)?shù)睦鋫€一兩天,女孩子就會想起你在的好處了。??
??
還有就是不要拿出“非你不娶”的志氣來,太掉價了不好,有時候可以耍點花招。??
??
4、要適當(dāng)?shù)膭?chuàng)造機會??
前面說了,不要使事情立刻變成“你在追別人”,而你又需要得到接近女孩子的機會,這時就要看你的創(chuàng)造力了。??
你可以搜集情報,想辦法把守株待兔變成一場邂逅;也可以裝做漫不經(jīng)心的找出最最充足的理由邀請對方和你一起做什么事。??
總之這個是最有技術(shù)含量的地方,實在不行可以找前輩請教。??
5、切忌切忌:隨便送人家禮物是不禮貌的??
有些人追女孩子心切,喜歡經(jīng)常買東西送人家,殊不知追女孩子最忌諱這個。??
俗話說“無功不受祿”,你這樣送人家東西就是在施加壓力,人家會覺得欠你的,所以會想辦法還給你,如果沒辦法還給你就會想辦法不和你交往,免得總是欠你人情。??
如果你想顯示自己的誠意,倒不妨請女孩子一起消費,比如說找好的餐廳吃飯,或者找貴的地方一起玩什么的,女孩子自然能看出你花了很多錢,但錢終究是兩個人一起花了而不是變成東西帶回家。??
??
三、“女朋友”到底是什么???
??
1、“女朋友”是一種事
實,而不是一份承諾??
你和女孩子開始交往,從“普通朋友”變成“好朋友”,再到“非常非常好、無話不談的朋友”,某一個陽光燦爛的午后,你“不小心”拉了她的手;“月上柳梢頭”,你突然襲擊吻了她。這時她就已經(jīng)是你的女朋友了,無論她是否承認(rèn),她心理已經(jīng)認(rèn)為你是他男友了。??
我知道最高明的,直到上床了都沒問過“你是否愿意做我女朋友”,最后還是女孩子急了:“你怎么還不求我做你女朋友啊!”??
所以說,千萬不要急于把窗戶紙捅破,情況越朦朧對你越有利。??
??
2、“表白”是什么???
前面說了,表白實際上就是一個形式而已,正確的順序應(yīng)該是:事實上已經(jīng)成為你女朋友了,你才能向人家表白,水到渠成。 很多人弄不明白這個問題,總以為人家先答應(yīng)做自己女朋友,然后再如何如何,我只能說他非常非常“單純”,也非常非常“愚蠢”。??
??
3、有沒有“迫不得已非表白不可”的時候???
??
有,比如說出現(xiàn)第三者,或者你和女孩子關(guān)系沒有成熟但兩個人可能分開一段時間。??
這時候的表白就是條件不成熟的表白,風(fēng)險非常大,類似于下圍棋的時候形勢嚴(yán)峻,落後的一方迫于無奈放出“勝負(fù)手”,贏了就贏了,輸了也只能說“倒霉都是天生的”。??
??
4、“愛”字不要輕易出口??
經(jīng)常看見論壇出現(xiàn)“大膽的表白”,說實話我真的認(rèn)為這是非常不成熟的一種表現(xiàn)。“愛”是一個神圣的字,意味著追求,也意味著承諾,甚至體現(xiàn)出一種責(zé)任。??
隨便說“愛”的男人是不負(fù)責(zé)任的。??
??
四、文明戀愛,不可強求??
??
1、不是每個mm都能追到手的??
好女孩總會有很多人追,不可能遂了每個人的心愿,總會有失敗者。舉個例子,就算你刻苦鉆研掌握了最搞超的追mm原理,你一樣追不上twins里的任何一個。??
換個角度考慮問題,一個小學(xué)沒畢業(yè)的農(nóng)村小保姆,即使對你再好,每個月賺600給你買700的禮物(透支),愿意為你“當(dāng)牛做馬”,你也不會愛上她。如果她每天哭哭啼啼的纏著,你肯定覺得煩。??
所以說愛情是需要物質(zhì)基礎(chǔ)的,至少需要平衡。??
??
2、追mm做是一種嚴(yán)肅的社會活動??
千萬不要把人家搞煩了,要給自己留后路。大丈夫何患無妻?有些mm確實勢利眼(少數(shù)),如果不服氣,你可以發(fā)憤圖強,用事實證明“她當(dāng)時瞎了眼”,絕對不要誤人誤己。 ??
??
最后補充一點千萬不要在mm面前顯得憤世嫉俗,憤世嫉俗有時候意味著“你很失敗”
posted @
2006-02-21 16:51 阿成 閱讀(466) |
評論 (3) |
編輯 收藏