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