Kava Pava Gava Tava Nava Zava Java

          everything about Java
          隨筆 - 15, 文章 - 0, 評論 - 1, 引用 - 0
          數(shù)據(jù)加載中……

          Hibernate 的 Proxy 陷阱

          對于使用框架,當然越是透明越好。在這一點上,Hibernate 做的相當不錯,算是非常透明的了。但透明并不是免費的 (Freedom is not free) 。每個框架或多或少總得有些墻,而墻也變得透明的時候,我們通常只有在一頭撞上去的時候才不得不付出代價。那個時候,我們才會揉著腦袋說 - 哦,原來這里還有一堵墻啊。。。

          閑話少說。本文是閱讀下面這篇文章的總結(jié)。

          http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/

          首先,什么是Proxy?這個可以參考一下GoF (著名的軟件“四人幫”Gang of Four)提出的《設計模式》。簡而言之,就是一個子類,在父類的基礎上,實現(xiàn)一點附加功能,而將其他請求全都交給父類去實現(xiàn),因而從用戶角度看子類可以完成全部父類的功能以及子類自己附加的功能,所以可以代替父類使用。

          Hibernate 使用 Proxy 實現(xiàn) Lazy Loading 功能。 比如 Person 類有個成員,也是 Person 類,叫做 boss。如果使用 Lazy Loading,在加載一個 Person 的時候,不會自動加載其 boss 的數(shù)據(jù),Hibernate 會自動給 Person 類生成一個 Proxy,將其 boss 的 ID 付給這個 Proxy。只有在訪問 boss 的具體數(shù)據(jù)的時候,這個 Proxy 才會自動調(diào)取數(shù)據(jù)。

          一個有趣的現(xiàn)象。如果我們使用圖形化調(diào)試器(比如 Eclipse)。當我們點開調(diào)試器中的 boss 的實例查看其數(shù)據(jù)的時候,這個 Proxy 就會去調(diào)取數(shù)據(jù)。這可能會使得調(diào)試和實際執(zhí)行的行為不一致。

          陷阱1:直接訪問成員變量

          Proxy 會將函數(shù)訪問轉(zhuǎn)到其父類的同樣函數(shù)處理。但是 Proxy 自己是不會持有數(shù)據(jù)的,其自己的成員變量(比如 boss 的姓名)都是 null。 比如,一個 Person 的 equals 函數(shù)可能會這樣寫:

            @Override
            
          public boolean equals(Object obj) {
              
          if (obj == null) {
                
          return false;
              }
              
          if (obj == this) {
                
          return true;
              }
              
          if (!(obj instanceof Person)) {
                
          return false;
              }
              
          return name.equals((Person)obj).name);
            }


          上面高亮的那句話看起來沒什么問題,也是常見寫法。可是,當被傳進來的 obj 可能是個 Proxy 的時候,直接訪問 obj 的 name 成員變量就不對了 - 因為這永遠是 null。因此,訪問另一個 obj 的成員變量時要用 getter / setter。

          陷阱2:instanceOf

          如果用 instanceOf 判斷一個對象是否是 Person 類,那么就沒有考慮到 Proxy 的情況。文章給出的建議是關(guān)掉 lazy loading,恐怕不是個很好的建議??梢钥紤]用 Class.isAssignableFrom 吧。

          后記:

          文章后面有些討論,就不再詳細討論或者翻譯了。有下面幾點可能有幫助(很有些人說了些 Hibernate 的風涼話呢):

          “@Peter: Actually, you don’t need to write equals/hashcode for proxies for that reason: Hibernate will enforce that every entity is represented by a single instance in a session, also for proxies. It will lookup a proxy instance if needed in an internal map, that is bound to the session.”


          “To know the class of the proxy object, you can use the method
          Class getClassWithoutInitializingProxy(Object object)
          form org.hibernate.proxy.HibernateProxyHelper
          /**
          * Get the class of an instance or the underlying class
          * of a proxy (without initializing the proxy!). It is
          * almost always better to use the entity name!
          */”

          “Actually there are some architectural problems resulting from pitfall 2.
          There are some cases where you don’t want to expose a (visible) setter which could initialize the object…
          Read here:
          http://www.bb242.de/2008/04/02/how-to-live-with-hibernate-proxies/

          A pretty neat workaround some things is to work with get() instead of load().”

          “Regarding Proxies in general: The Hibernate approach is the we-can-implement-it-on-a-weekend approach. Whereas JDO has featured a smarter approach (available in many JPA implementations), i.e. use byte code enhancement to implement the proxy functionality in the class itself, which solves most of the problems. (But you can’t design and implement that on a weekend.)”


          “Bytecode-enhancing the actual class would be great but in runtime is hard to do because they need to be enhanced before they are ever used which is complex.

          A simpler alternative is to create a proxy for the actual object itself and *not* have the “target” kludge. Simply use the fields in the proxy directly. This still does not properly solve the inheritance scheme but that is impossible with lazy loading anyway.

          The simpler alternative has way less problems than the current implementation and *can* be built in an afternoon (my replacement for Hibernate called SPF has it, and it took that long ;-)

          Sadly, Hibernate sucks bigtime and is not a good persistence framework at all; it is just the one that sucks the least…

          posted on 2010-01-11 12:15 bing 閱讀(3572) 評論(0)  編輯  收藏 所屬分類: Hibernate

          主站蜘蛛池模板: 宜春市| 永春县| 修文县| 杭州市| 鲁山县| 襄汾县| 深圳市| 彰武县| 宁明县| 庆城县| 榆树市| 郴州市| 茂名市| 偏关县| 珲春市| 汝南县| 连州市| 三亚市| 阆中市| 徐闻县| 鄂州市| 遂平县| 通辽市| 玉龙| 临高县| 华坪县| 云安县| 温州市| 铁岭市| 八宿县| 永康市| 武强县| 广安市| 东至县| 日土县| 沁源县| 沾化县| 青神县| 泾川县| 东至县| 松溪县|