javascript
Spring开发人员知道的一件事
在最近關(guān)于(核心)Spring Framework的培訓(xùn)課程中,有人問我:“(Java)Spring開發(fā)人員是否應(yīng)該知道一件事,那應(yīng)該是什么?” 這個問題使我措手不及。 是的,(核心)Spring框架確實涵蓋了很多領(lǐng)域(例如,bean,配置,面向方面的編程,事務(wù))。 我很難只指出一件事。 最后,我提到了我們?yōu)槠?天的培訓(xùn)課程所涵蓋的所有內(nèi)容。
如果(Java)Spring開發(fā)人員應(yīng)該知道的一件事,那應(yīng)該是什么?
當(dāng)我進一步思考這個問題時,我開始思考最重要的一個問題。 最后,我想到了Spring如何最重要地使用方面將行為添加到托管對象(通常稱為bean)中。 Spring Framework通過這種方式來支持事務(wù),安全性,范圍,基于Java的配置等。 我在這篇文章中分享我的想法。
最后,我想到了Spring如何最重要地使用方面將行為添加到托管對象(通常稱為bean)中。
ORM和延遲加載異常
大多數(shù)使用某種形式的ORM的開發(fā)人員都遇到了一個異常,該異常表明無法加載子實體(例如LazyInitializationException )。
一些遇到這種情況的開發(fā)人員將使用“打開的視圖中的會話”( OSIV )模式來保持會話打開并防止發(fā)生此異常。 但是我覺得這太過分了。 更糟糕的是,一些開發(fā)人員認(rèn)為“開放會話可見”模式是唯一的解決方案。 造成這種誤解的潛在根本原因可能是,開發(fā)人員可能不了解有效使用Spring Framework來保持ORM會話打開時間更長的知識。
對于JPA ,“打開視圖中的實體管理器”模式將在請求開始時創(chuàng)建一個實體管理器,將其綁定到請求線程,并在響應(yīng)完成時將其關(guān)閉。
那么,如果不是OSIV模式,哪種解決方案更好?
簡短的答案是使用Spring框架在需要的時間內(nèi)保持會話打開(例如@Transactional )。 請繼續(xù)閱讀,因為我會提供更長的答案。
服務(wù)和存儲庫
在分層體系結(jié)構(gòu)中,典型的設(shè)計模式是定義域或應(yīng)用程序服務(wù) (通常定義為接口)以提供業(yè)務(wù)功能(例如,開始使用購物車,向該購物車添加商品,搜索產(chǎn)品)。 域和應(yīng)用程序服務(wù)的實現(xiàn)通常會將域?qū)嶓w的檢索/持久性委派給存儲庫。
存儲庫 (或數(shù)據(jù)訪問對象)也被定義為檢索/持久化域?qū)嶓w(即提供ORM和CRUD訪問)的接口。 自然地,存儲庫實現(xiàn)使用ORM庫(例如JPA / Hibernate,myBATIS)來檢索和持久化域?qū)嶓w。 這樣,它使用ORM框架的類連接到持久性存儲,檢索/持久化實體并關(guān)閉連接(在Hibernate中稱為會話)。 此時,沒有延遲加載失敗的問題。
當(dāng)服務(wù)使用資料庫中檢索域?qū)嶓w,并希望加載的子實體(庫方法返回之后 )發(fā)生的懶加載失敗問題。 到存儲庫返回域?qū)嶓w時,ORM會話將關(guān)閉。 因此,嘗試訪問/加載域服務(wù)中的子實體會導(dǎo)致異常。
下面的代碼段說明了當(dāng)訂單實體的子項目由存儲庫返回后被延遲加載時,如何發(fā)生延遲加載異常。
@Entity public class Order {@OneToMany // defaults to FetchType.LAZYprivate List<OrderItem> items;…public List<OrderItem> getItems() {…} }public class SomeApplicationServiceImpl implements SomeApplicationService {private OrderRepository orderRepository;…@Overridepublic void method1(…) {…order = orderRepository.findById(...);order.getItems(); // <-- Lazy loading exception occurs!…}… }public class OrderRepositoryImpl implements OrderRepository {@PersistenceContextprivate EntityManager em;…@Overridepublic Order findById(...) {...}… }存儲庫實現(xiàn)將JPA明確用于其ORM(如使用EntityManager )。
在這一點上,一些開發(fā)人員可能選擇使用緊急獲取來防止延遲初始化異常。 告訴ORM急切地獲取訂單實體的子項將起作用。 但是有時候,我們不需要加載子項。 急于加載它可能是不必要的開銷。 僅在需要時加載它會很棒。
為了防止延遲初始化異常(而不是被迫急于獲取),我們需要保持ORM會話打開,直到調(diào)用服務(wù)方法返回。 在Spring中,可以像@Transactional一樣簡單地注釋服務(wù)方法以保持會話打開。 我發(fā)現(xiàn)這種方法比使用“在視圖中打開會話”模式(或被迫使用急切獲取)更好,因為它使會話僅在我們希望的時間內(nèi)保持打開狀態(tài)。
public class SomeApplicationServiceImpl implements SomeApplicationService {private OrderRepository orderRepository;…@Override@Transactional // <-- open the session (if it's not yet open)public void method1(…) {…order = orderRepository.findById(...);order.getItems(); // <-- Lazy loading exception should not happen…}… }表示層中的域?qū)嶓w
即使將ORM會話在服務(wù)層中(在存儲庫實現(xiàn)對象之外)保持打開狀態(tài),當(dāng)我們將域?qū)嶓w暴露給表示層時,仍然可能發(fā)生惰性初始化異常。 同樣,由于這個原因,一些開發(fā)人員更喜歡OSIV方法,因為它還可以防止表示層中的延遲初始化異常。
但是,為什么要在表示層中公開域?qū)嶓w?
根據(jù)經(jīng)驗,我曾與那些希望在表示層中公開域?qū)嶓w的團隊合作。 這通常會導(dǎo)致貧血領(lǐng)域模型 ,因為表示層框架需要一種將輸入值綁定到對象的方法。 這迫使域?qū)嶓w具有g(shù)etter和setter方法以及零參數(shù)構(gòu)造函數(shù)。 具有g(shù)etter和setter將使不變式難以執(zhí)行。 對于簡單域,這是可行的。 但是對于更復(fù)雜的領(lǐng)域,更豐富的領(lǐng)域模型將是首選,因為它更易于實施不變式。
在更豐富的域模型中,表示表示層輸入/輸出值的對象實際上是數(shù)據(jù)傳輸對象(DTO)。 它們代表在域?qū)又袌?zhí)行的輸入(或命令)。 考慮到這一點,我更喜歡使用DTO并維護更豐富的域模型。 因此,我并沒有真正在表示層遇到懶惰的初始化異常。
向受管對象添加行為的方面
Spring會攔截對這些@Transactional注釋方法的調(diào)用,以確保ORM會話處于打開狀態(tài)。
事務(wù)(或只是保持ORM會話保持打開狀態(tài))并不是使用方面提供的唯一行為。 有安全性,范圍,基于Java的配置等。 知道Spring框架使用方面來添加行為是我們讓Spring管理我們開發(fā)的POJO的關(guān)鍵原因之一。
結(jié)論
妳去 對我來說,這是Spring Framework開發(fā)人員在使用內(nèi)核時應(yīng)了解的最重要的一件事。 現(xiàn)在,我已經(jīng)對什么是最重要的事情發(fā)表了意見,您呢? 在處理Core Spring時,您認(rèn)為最重要的一件事是。 干杯!
翻譯自: https://www.javacodegeeks.com/2016/02/one-thing-good-spring-developers-know.html
總結(jié)
以上是生活随笔為你收集整理的Spring开发人员知道的一件事的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 芯动风华GPU赋能卓怡恒通桌面计算 实现
- 下一篇: 在Eclipse上创建JSF / CDI