亚洲AV日韩AⅤ综合手机在线观看,激情婷婷久久综合色,欧美色五月婷婷久久,久久国产精品99久久人人澡

  • <abbr id="uk6uq"><abbr id="uk6uq"></abbr></abbr>
  • <tbody id="uk6uq"></tbody>
  • J2EE應(yīng)用下基于AOP的抓取策略

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

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

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

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

      Department有0或多個(gè)employees。

      Employee屬于0或1個(gè)department。

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

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

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

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

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

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

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

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

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

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

      為了解決上面這些問題,Repository/DAO層需要根據(jù)不同的業(yè)務(wù)情況執(zhí)行不同的查詢來獲取實(shí)體。就像Aspect類所定義的那樣,我們可以根據(jù)特定的操作使用不同的抓取機(jī)制來覆蓋Repository/DAO類所定義的默認(rèn)抓取模式。所有的抓取模式類都實(shí)現(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ù)實(shí)際情況進(jìn)行調(diào)整。我們決定將Repository層的抓取策略調(diào)整到 Repository和Service層外,放在一個(gè)Aspect類中,這樣當(dāng)需要增加新的業(yè)務(wù)邏輯時(shí)只需修改Aspect類并增加一個(gè)針對(duì)于 Repository的抓取策略實(shí)現(xiàn)即可。這里我們使用了面向方面的編程(Aspect Oriented Programming)以根據(jù)業(yè)務(wù)的不同使用不同的抓取策略。什么是面向方面的編程?面向方面的編程(AOP)可以通過模塊化的形式實(shí)現(xiàn)實(shí)際應(yīng)用中的橫切關(guān)注點(diǎn),如日志、追蹤、動(dòng)態(tài)分析、錯(cuò)誤處理、服務(wù)水平協(xié)議、策略增強(qiáng)、池化、緩存、并發(fā)控制、安全、事務(wù)管理以及業(yè)務(wù)規(guī)則等等。對(duì)這些關(guān)注點(diǎn)的傳統(tǒng)實(shí)現(xiàn)方式需要我們將這些實(shí)現(xiàn)融合到模塊的核心關(guān)注點(diǎn)中。憑借AOP,我們可以在一個(gè)叫做方面(aspect)的獨(dú)立模塊中實(shí)現(xiàn)這些關(guān)注點(diǎn)。模塊化的結(jié)果就是設(shè)計(jì)簡化、易于理解、質(zhì)量提升、開發(fā)時(shí)間降低以及對(duì)系統(tǒng)需求變更的快速響應(yīng)。接下來讀者朋友們可以參考 Ramnivas Laddad所著的《AspectJ in Action》一書以詳細(xì)了解AspectJ的概念以及編程方式,還可以了解一下AspectJ的開發(fā)工具。Aspect在抓取策略實(shí)現(xiàn)上扮演著重要角色。抓取策略是個(gè)業(yè)務(wù)層的橫切關(guān)注點(diǎn),它會(huì)隨著業(yè)務(wù)的變化而變化。Aspect對(duì)于特定的業(yè)務(wù)邏輯下使用何種抓取策略起到了至關(guān)重要的作用。這里我們將對(duì)抓取策略的管理放在了底層服務(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í)行何種查詢的邏輯就成為一個(gè)橫切關(guān)注點(diǎn)了,它被放在Aspect中。Aspect會(huì)根據(jù)業(yè)務(wù)規(guī)則的不同在Service層調(diào)用Repository層的API之前將抓取策略注入到Repository中。這樣我們就可以使用相同的Service和 Repository層API來滿足各種不同的業(yè)務(wù)規(guī)則了。來看個(gè)具體示例吧,該示例會(huì)同時(shí)抓取一個(gè)employee的Department和Dependent的詳細(xì)信息。我們需要對(duì)業(yè)務(wù)層進(jìn)行一些變更,增加一個(gè)方法:getEmployeeWithDepartmentAndDependentsDetails(int employeeId)。實(shí)現(xiàn)新的抓取策略類EmployeeWithDepartmentAndDependentFetchingStaratergy,后者又實(shí)現(xiàn)了EmployeeFetchingStrategy并重寫了queryEmployeeById方法,該方法會(huì)返回優(yōu)化后的查詢,可以在一個(gè)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和一個(gè)新的FetchingStrategy實(shí)現(xiàn)就完成了上述新增的業(yè)務(wù)。現(xiàn)在我們來談?wù)勱P(guān)于二級(jí)緩存的查詢優(yōu)化問題。在上面的示例代碼中,我們對(duì)department實(shí)體進(jìn)行一些修改并配置在二級(jí)緩存中。如果對(duì) department實(shí)體采取預(yù)先抓取,那么對(duì)于同樣的department實(shí)例,縱使它位于二級(jí)緩存中,每次也都需要查詢數(shù)據(jù)庫。如果不在查詢中獲取 department實(shí)體,那么業(yè)務(wù)層就需要參與到事務(wù)當(dāng)中,因?yàn)槲覀儾]有將department實(shí)體緩存起來而是通過延遲加載的方式得到它。這樣,事務(wù)聲明就從底層移到了業(yè)務(wù)層,雖然我們知道該業(yè)務(wù)需要哪些數(shù)據(jù),但O/R Mapping工具卻沒有提供相應(yīng)的機(jī)制來解決上面遇到的問題,即預(yù)先抓取緩存中的數(shù)據(jù)。對(duì)于那些沒有緩存的數(shù)據(jù)來說這種方式?jīng)]什么問題,但對(duì)于緩存數(shù)據(jù)來說,這就依賴于O/R Mapping工具了,因?yàn)橹挥兴拍芙鉀Q緩存數(shù)據(jù)問題。該示例附帶的源代碼詳細(xì)解釋了抓取策略。該zip文件含有一個(gè)工程示例,闡述了上面談到的所有場景。你可以使用任何IDE或是使用aspectj編譯器從命令行執(zhí)行代碼。在執(zhí)行前請(qǐng)確保jdbc.properties文件與你機(jī)器上的信息一致并創(chuàng)建示例應(yīng)用所需的表。你可以使用Eclipse IDE以及AJDT插件運(yùn)行代碼,請(qǐng)按照下面的步驟進(jìn)行:解壓縮下載好的代碼并將工程導(dǎo)入到Eclipse中。

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

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

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

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

    J2EE控制策略03-09

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

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

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

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

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

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

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

    J2EE應(yīng)用服務(wù)器介紹03-20