1. <tt id="5hhch"><source id="5hhch"></source></tt>
    1. <xmp id="5hhch"></xmp>

  2. <xmp id="5hhch"><rt id="5hhch"></rt></xmp>

    <rp id="5hhch"></rp>
        <dfn id="5hhch"></dfn>

      1. J2EE應用下基于AOP的抓取策略

        時間:2024-07-14 10:44:24 J2EE培訓 我要投稿
        • 相關推薦

        J2EE應用下基于AOP的抓取策略

          如何通過最精簡的SQL查詢獲取所需的數據。很多時候這可不是輕而易舉的事情。默認情況下,O/R Mapping工具會按需加載數據,除非你改變了其默認設置。延遲加載行為保證了依賴的數據只有在真正請求時才會被加載進來,這樣就可以避免創建無謂的對象。有時我們的業務并不會使用到依賴的那些組件,這時延遲加載就派上用場了,同時也無需加載那些用不上的組件了。

          典型情況下,我們的業務很清楚需要哪些數據。但由于使用了延遲加載,在執行大量Select查詢時數據庫的性能會降低,因為業務所需的數據并不是一下子獲得的。這樣,對于那些需要支持大量請求的應用來說可能會產生瓶頸(可伸縮性問題)。來看個例子吧,假設某個業務流程想要得到一個Person及其Address信息。我們將Address組件配置成延遲加載,這樣要想得到所需的數據就需要更多的SQL查詢,也就是說首先查詢Person,然后再查詢Address。這增加了數據庫與應用之間的通信成本。解決辦法就是在一個單獨的查詢中將 Person和Address都得到,因為我們知道這兩個組件都是業務流程所需的。如果在DAO/Repository及底層Service開發特定于業務的Fetching-API,對于那些擁有不同數據集的相同領域對象來說,我們就得編寫不同的API進行抓取并組裝了。這么做會使Repository及底層Service過于膨脹,最終變成維護的夢魘。延遲抓取的另一個問題就是在獲取到請求的數據前要一直打開數據庫連接,否則應用就會拋出一個延遲加載異常。說明:如果在查詢中使用預先抓取來獲取二級緩存中的數據時,我們將無法解決上面提出的問題。對于Hibernate來說,如果我們使用預先抓取來獲取二級緩存中的數據,那么它將從數據庫而不是緩存中去獲取數據,哪怕是二級緩存中已經存在該數據。這就說明Hibernate也沒有解決這個問題,從而表明我們不應該在查詢中通過預先抓取來獲得二級緩存中的對象。對于那些可以讓我們調節查詢以獲取緩存對象的O/R Mapping工具來說,如果緩存中有對象就會從緩存中獲取,否則采取預先抓取的方式。這就解決了上面提到的事務/DB連接問題,因為在查詢的執行過程中會同時獲取緩存中的數據而不是按需讀取(也就是延遲加載)。通過下面的示例代碼來了解一下延遲加載所面對的問題及解決辦法?紤]如下場景:某領域中有3個實體,分別是Employee、Department及Dependent。這三個實體之間的關系如下:Employee有0或多個dependents。

          Department有0或多個employees。

          Employee屬于0或1個department。

          我們要執行三個操作:獲取employee的詳細信息。

          獲取employee及其dependent的詳細信息。

          獲取employee及其department的詳細信息。

          以上三個操作需要獲取并呈現不同的數據。使用延遲加載有如下弊端:如果對實體employee所關聯的dependent和department這兩個實體使用延遲加載,那么在操作2和3中就會生成更多的SQL查詢語句。

          在多個查詢語句的執行過程中需要保持數據庫連接,否則會拋出一個延遲加載異常,這將導致數據出現問題。

          但另一方面,使用預先抓取也存在如下弊端:對employee所對應的dependents和department采取預先抓取會產生不必要的數據。

          無法在特定的場景下對查詢進行調優。

          在Repository/DAO或底層服務中使用特定于操作的API可以解決上述問題,但卻會導致如下問題:代碼膨脹——不管是Service還是Repository/DAO類都無法幸免。

          維護的夢魘——不管是Service還是Repository/DAO層,只要有新的操作都需要增加新的API。

          代碼重復——有時底層服務需要在獲取的實體上增加某些業務邏輯,與之類似,還要在數據返回前檢查DAO/Repository層的查詢響應以驗證數據可用性。

          為了解決上面這些問題,Repository/DAO層需要根據不同的業務情況執行不同的查詢來獲取實體。就像Aspect類所定義的那樣,我們可以根據特定的操作使用不同的抓取機制來覆蓋Repository/DAO類所定義的默認抓取模式。所有的抓取模式類都實現了相同的接口。

          Repository類使用了上述的抓取模式來執行查詢,如下代碼所示:public Employee findEmployeeById(int employeeId) {

          List employee = hibernateTemplate.find(fetchingStrategy.queryEmployeeById(),

          new Integer(employeeId));

          if(employee.size() == 0)

          return null;

          return (Employee)employee.get(0);

          }

          Repository類中的employee的抓取策略需要根據實際情況進行調整。我們決定將Repository層的抓取策略調整到 Repository和Service層外,放在一個Aspect類中,這樣當需要增加新的業務邏輯時只需修改Aspect類并增加一個針對于 Repository的抓取策略實現即可。這里我們使用了面向方面的編程(Aspect Oriented Programming)以根據業務的不同使用不同的抓取策略。什么是面向方面的編程?面向方面的編程(AOP)可以通過模塊化的形式實現實際應用中的橫切關注點,如日志、追蹤、動態分析、錯誤處理、服務水平協議、策略增強、池化、緩存、并發控制、安全、事務管理以及業務規則等等。對這些關注點的傳統實現方式需要我們將這些實現融合到模塊的核心關注點中。憑借AOP,我們可以在一個叫做方面(aspect)的獨立模塊中實現這些關注點。模塊化的結果就是設計簡化、易于理解、質量提升、開發時間降低以及對系統需求變更的快速響應。接下來讀者朋友們可以參考 Ramnivas Laddad所著的《AspectJ in Action》一書以詳細了解AspectJ的概念以及編程方式,還可以了解一下AspectJ的開發工具。Aspect在抓取策略實現上扮演著重要角色。抓取策略是個業務層的橫切關注點,它會隨著業務的變化而變化。Aspect對于特定的業務邏輯下使用何種抓取策略起到了至關重要的作用。這里我們將對抓取策略的管理放在了底層服務和Respository層之外。任何新的業務都可能需要不同的抓取策略,這樣我們就無需修改底層服務或是Respository層的API就能應用新的抓取策略了。FetchingStrategyAspect.aj/**

          Identify the getEmployeeWithDepartmentDetails flow where you need to change the fetching

          strategy at repository level

          */

          pointcut empWithDepartmentDetail(): call(* EmployeeRepository.findEmployeeById(int))

          && cflow(execution(* EmployeeDetailsService.getEmployeeWithDepartmentDetails(int)));

          /**

          When you are at the specified poincut before continuing further update the fetchingStrategy in

          EmployeeRepositoryImpl to EmployeeWithDepartmentFetchingStrategy

          */

          before(EmployeeRepositoryImpl r): empWithDepartmentDetail() && target(r) {

          r.fetchingStrategy = new EmployeeWithDepartmentFetchingStrategy();

          }

          /**

          Identify the getEmployeeWithDependentDetails flow where you need to change the fetching

          staratergy at repository level

          */

          pointcut empWithDependentDetail(): call(* EmployeeRepository.findEmployeeById(int))

          && cflow(execution(* EmployeeDetailsService.getEmployeeWithDependentDetails(int)));

          /**

          When you are at the specified poincut before continuing further update the fetchingStrategy in

          EmployeeRepositoryImpl to EmployeeWithDependentFetchingStrategy

          */

          before(EmployeeRepositoryImpl r): empWithDependentDetail() && target(r) {

          r.fetchingStrategy = new EmployeeWithDependentFetchingStrategy();

          }

          這樣,Repository到底要執行何種查詢就不是由Service和Repository層所決定了,而是由外面的Aspect決定,縱使增加了新的業務也無需修改底層服務和Repository層。決定執行何種查詢的邏輯就成為一個橫切關注點了,它被放在Aspect中。Aspect會根據業務規則的不同在Service層調用Repository層的API之前將抓取策略注入到Repository中。這樣我們就可以使用相同的Service和 Repository層API來滿足各種不同的業務規則了。來看個具體示例吧,該示例會同時抓取一個employee的Department和Dependent的詳細信息。我們需要對業務層進行一些變更,增加一個方法:getEmployeeWithDepartmentAndDependentsDetails(int employeeId)。實現新的抓取策略類EmployeeWithDepartmentAndDependentFetchingStaratergy,后者又實現了EmployeeFetchingStrategy并重寫了queryEmployeeById方法,該方法會返回優化后的查詢,可以在一個SQL語句中獲取所需數據。由Aspect將上述的抓取策略注入到相關的業務中,如下所示:pointcut empWithDependentAndDepartmentDetail(): call(* EmployeeRepository.findEmployeeById(int))

          && cflow(execution(* EmployeeDetailsService.getEmployeeWithDepartmentAndDependentsDetails(int)));

          before(EmployeeRepositoryImpl r): empWithDependentAndDepartmentDetail() && target(r) {

          r.fetchingStrategy = new EmployeeWithDepartmentAndDependentFetchingStaratergy();

          }

          如你所見,我們并沒有修改底層業務與Repository層而是使用Aspect和一個新的FetchingStrategy實現就完成了上述新增的業務,F在我們來談談關于二級緩存的查詢優化問題。在上面的示例代碼中,我們對department實體進行一些修改并配置在二級緩存中。如果對 department實體采取預先抓取,那么對于同樣的department實例,縱使它位于二級緩存中,每次也都需要查詢數據庫。如果不在查詢中獲取 department實體,那么業務層就需要參與到事務當中,因為我們并沒有將department實體緩存起來而是通過延遲加載的方式得到它。這樣,事務聲明就從底層移到了業務層,雖然我們知道該業務需要哪些數據,但O/R Mapping工具卻沒有提供相應的機制來解決上面遇到的問題,即預先抓取緩存中的數據。對于那些沒有緩存的數據來說這種方式沒什么問題,但對于緩存數據來說,這就依賴于O/R Mapping工具了,因為只有它才能解決緩存數據問題。該示例附帶的源代碼詳細解釋了抓取策略。該zip文件含有一個工程示例,闡述了上面談到的所有場景。你可以使用任何IDE或是使用aspectj編譯器從命令行執行代碼。在執行前請確保jdbc.properties文件與你機器上的信息一致并創建示例應用所需的表。你可以使用Eclipse IDE以及AJDT插件運行代碼,請按照下面的步驟進行:解壓縮下載好的代碼并將工程導入到Eclipse中。

          配置Resources/dbscript目錄下的jdbc.properties文件中的數據庫信息。

          完成上面的步驟后請執行resources\dbscript\tables.sql腳本,這將創建該示例應用所需的表。

          以AspectJ/Java應用的方式運行Main.java文件來創建默認數據并測試上面的抓取策略實現。

        【J2EE應用下基于AOP的抓取策略】相關文章:

        J2EE控制策略03-09

        基于信息化下的品牌管理提升策略研究03-05

        高性能J2EE應用的技巧03-22

        J2EE應用的十個技巧03-26

        構建高性能J2EE應用的技巧03-20

        J2EE應用服務器03-29

        廣告設計應用策略03-13

        Java動態代理實現AOP的方法03-16

        J2EE應用服務器介紹03-20

        国产高潮无套免费视频_久久九九兔免费精品6_99精品热6080YY久久_国产91久久久久久无码

        1. <tt id="5hhch"><source id="5hhch"></source></tt>
          1. <xmp id="5hhch"></xmp>

        2. <xmp id="5hhch"><rt id="5hhch"></rt></xmp>

          <rp id="5hhch"></rp>
              <dfn id="5hhch"></dfn>