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應(yīng)用下基于AOP的抓取策略

        時間:2024-07-14 10:44:24 J2EE培訓(xùn) 我要投稿
        • 相關(guān)推薦

        J2EE應(yīng)用下基于AOP的抓取策略

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

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

          Department有0或多個employees。

          Employee屬于0或1個department。

          我們要執(zhí)行三個操作:獲取employee的詳細(xì)信息。

          獲取employee及其dependent的詳細(xì)信息。

          獲取employee及其department的詳細(xì)信息。

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

          在多個查詢語句的執(zhí)行過程中需要保持?jǐn)?shù)據(jù)庫連接,否則會拋出一個延遲加載異常,這將導(dǎo)致數(shù)據(jù)出現(xiàn)問題。

          但另一方面,使用預(yù)先抓取也存在如下弊端:對employee所對應(yīng)的dependents和department采取預(yù)先抓取會產(chǎn)生不必要的數(shù)據(jù)。

          無法在特定的場景下對查詢進(jìn)行調(diào)優(yōu)。

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

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

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

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

          Repository類使用了上述的抓取模式來執(zhí)行查詢,如下代碼所示: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的抓取策略需要根據(jù)實際情況進(jìn)行調(diào)整。我們決定將Repository層的抓取策略調(diào)整到 Repository和Service層外,放在一個Aspect類中,這樣當(dāng)需要增加新的業(yè)務(wù)邏輯時只需修改Aspect類并增加一個針對于 Repository的抓取策略實現(xiàn)即可。這里我們使用了面向方面的編程(Aspect Oriented Programming)以根據(jù)業(yè)務(wù)的不同使用不同的抓取策略。什么是面向方面的編程?面向方面的編程(AOP)可以通過模塊化的形式實現(xiàn)實際應(yīng)用中的橫切關(guān)注點(diǎn),如日志、追蹤、動態(tài)分析、錯誤處理、服務(wù)水平協(xié)議、策略增強(qiáng)、池化、緩存、并發(fā)控制、安全、事務(wù)管理以及業(yè)務(wù)規(guī)則等等。對這些關(guān)注點(diǎn)的傳統(tǒng)實現(xiàn)方式需要我們將這些實現(xiàn)融合到模塊的核心關(guān)注點(diǎn)中。憑借AOP,我們可以在一個叫做方面(aspect)的獨(dú)立模塊中實現(xiàn)這些關(guān)注點(diǎn)。模塊化的結(jié)果就是設(shè)計簡化、易于理解、質(zhì)量提升、開發(fā)時間降低以及對系統(tǒng)需求變更的快速響應(yīng)。接下來讀者朋友們可以參考 Ramnivas Laddad所著的《AspectJ in Action》一書以詳細(xì)了解AspectJ的概念以及編程方式,還可以了解一下AspectJ的開發(fā)工具。Aspect在抓取策略實現(xiàn)上扮演著重要角色。抓取策略是個業(yè)務(wù)層的橫切關(guān)注點(diǎn),它會隨著業(yè)務(wù)的變化而變化。Aspect對于特定的業(yè)務(wù)邏輯下使用何種抓取策略起到了至關(guān)重要的作用。這里我們將對抓取策略的管理放在了底層服務(wù)和Respository層之外。任何新的業(yè)務(wù)都可能需要不同的抓取策略,這樣我們就無需修改底層服務(wù)或是Respository層的API就能應(yīng)用新的抓取策略了。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到底要執(zhí)行何種查詢就不是由Service和Repository層所決定了,而是由外面的Aspect決定,縱使增加了新的業(yè)務(wù)也無需修改底層服務(wù)和Repository層。決定執(zhí)行何種查詢的邏輯就成為一個橫切關(guān)注點(diǎn)了,它被放在Aspect中。Aspect會根據(jù)業(yè)務(wù)規(guī)則的不同在Service層調(diào)用Repository層的API之前將抓取策略注入到Repository中。這樣我們就可以使用相同的Service和 Repository層API來滿足各種不同的業(yè)務(wù)規(guī)則了。來看個具體示例吧,該示例會同時抓取一個employee的Department和Dependent的詳細(xì)信息。我們需要對業(yè)務(wù)層進(jìn)行一些變更,增加一個方法:getEmployeeWithDepartmentAndDependentsDetails(int employeeId)。實現(xiàn)新的抓取策略類EmployeeWithDepartmentAndDependentFetchingStaratergy,后者又實現(xiàn)了EmployeeFetchingStrategy并重寫了queryEmployeeById方法,該方法會返回優(yōu)化后的查詢,可以在一個SQL語句中獲取所需數(shù)據(jù)。由Aspect將上述的抓取策略注入到相關(guān)的業(yè)務(wù)中,如下所示:pointcut empWithDependentAndDepartmentDetail(): call(* EmployeeRepository.findEmployeeById(int))

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

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

          r.fetchingStrategy = new EmployeeWithDepartmentAndDependentFetchingStaratergy();

          }

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

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

          完成上面的步驟后請執(zhí)行resources\dbscript\tables.sql腳本,這將創(chuàng)建該示例應(yīng)用所需的表。

          以AspectJ/Java應(yīng)用的方式運(yùn)行Main.java文件來創(chuàng)建默認(rèn)數(shù)據(jù)并測試上面的抓取策略實現(xiàn)。

        【J2EE應(yīng)用下基于AOP的抓取策略】相關(guān)文章:

        J2EE控制策略03-09

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

        高性能J2EE應(yīng)用的技巧03-22

        J2EE應(yīng)用的十個技巧03-26

        構(gòu)建高性能J2EE應(yīng)用的技巧03-20

        J2EE應(yīng)用服務(wù)器03-29

        廣告設(shè)計應(yīng)用策略03-13

        Java動態(tài)代理實現(xiàn)AOP的方法03-16

        J2EE應(yīng)用服務(wù)器介紹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>