最愛Java

          書山有路勤為徑,學(xué)海無涯苦作舟

               摘要: 一. 捕獲方法調(diào)用         使用call(Signature)切入點。其語法:          pointcut <pointcut name>(<any values to be picked u...  閱讀全文
          posted @ 2008-07-03 22:17 Brian 閱讀(1520) | 評論 (2)編輯 收藏
          一. 安裝AspectJ
                  從最簡單的方面來說,AspectJ安裝很簡單:
                   1.從http://www.aspectj.org下載最新版本(目前版本是1.6.0)。
                   2.通過雙擊下載下來的JAR來安裝。其默認(rèn)安裝目錄為asprctj1.6目錄。
                   3.可在安裝目錄的bin目錄下調(diào)用ajc命令查看幫助。
                   4.使用AspectJ只需復(fù)制aspectjrt.jar即可。

          二. 第一個簡單的方面
                  
          簡單的業(yè)務(wù)邏輯Java類
          package com.oreilly.aspectjcookbook;

          public class MyClass {
              
          public void foo(int number , String name) {
                  System.out.println(
          "Inside foo(int , String)");
              }

              
              
          public static void main(String[] args) {
                  
          //Create an instance of MyClass
                  MyClass myObject = new MyClass();
                  
          //Make the call to foo
                  myObject.foo(1 , "Russ Miles");
              }

          }

                  AspectJ的簡單的HelloWorld方面
          package com.oreilly.aspectjcookbook;

          public aspect HelloWorld {
              pointcut callPointcut() :
                  call(
          void com.oreilly.aspectjcookbook.MyClass.foo(int,String));
              
              
              before() : callPointcut() 
          {
                  System.out.println(
          "Hello World");
                  System.out.println(
          "In the advice attached to the call pointcut");
              }

          }

          將上述兩個文件保存在同一目錄中,運行ajc命令,編譯這兩個文件,并產(chǎn)生方面和類的.class文件。
                  ajc -classpath %MY_CLASSPATH% -d %MY_DESTINATION_DIRECTORY% com/oreilly/aspectjcookbook/MyClass.java com/oreilly/aspectjcookbook/HelloWorld.java
          在使用上述命令過程中,需要確保aspectjrt.jar在你的類路徑中。
          ajc編譯器會將產(chǎn)生兩個.class文件:MyClass.class和HelloWorld.class。并可通過正常的java命令來運行:
                  java -classpath %MY_CLASSPATH% com.oreilly.aspectjcookbook.MyClass
          可得到如下結(jié)果:
                  Hello World
                  In the advice attached to the call pointcut  
                  Inside foo(int , String)
          是不是很簡單呢?現(xiàn)在我們來分析一下方面的每一行的含義:
           1package com.oreilly.aspectjcookbook;
           2
           3public aspect HelloWorld {
           4    pointcut callPointcut() :
           5        call(void com.oreilly.aspectjcookbook.MyClass.foo(int,String));
           6    
           7    
           8    before() : callPointcut() {
           9        System.out.println("Hello World");
          10        System.out.println("In the advice attached to the call pointcut");
          11    }

          12}


           第3行聲明了一個方法。
           第4行和第5行聲明單一命名的切入點的邏輯。切入點邏輯指定了應(yīng)用程序中的任何連接點,本例中會捕獲對void com.oreilly.aspectjcookbook.MyClass.foo(int,String)方法的調(diào)用。切入點被命名為callPointcut(),使得可以在方面的作用域內(nèi)的任意位置都可以引用它。
           第8行到11行聲明單一通知塊。before()通知只是簡單地指出它將在任何被callPointcut()切入點匹配的連接點之前執(zhí)行。
          注意:除了.java可作為后綴名以外,.aj也可以作為后綴名使用。ajc工具都會編譯所提供的文件。兩者沒有區(qū)別,只是個人喜好而已。

          三. 編譯一個方面和多個Java文件
              
          如果需要多個文件,那么按上述方法編譯是一件痛苦的事情。好在我們可以編寫一個AspectJ配置構(gòu)建文件。配置構(gòu)建文件的后綴名為.lst,其中包含了所有在編譯中需要使用的類文件和方面的名稱。如:
                  //File in file.lst
                  com/oreilly/aspectjcookbook/MyClass.java
                  com/oreilly/aspectjcookbook/MyAspect.java
                  com/oreilly/aspectjcookbook/AnotherClass.java
                  com/oreilly/aspectjcookbook/AnotherAspect.java
          然后使用如下命令編譯:
                  ajc -argfile file.lst -classpath %MY_CLASSPATH% -d %MY_DESTINATION_DIRECTORY%

          四. 織入方面到j(luò)ar中
              1.首先編譯MyClass.java并打包到MyApp.jar中
                  java -classpath %MY_CLASSPATH% -d %MY_DESTINATION_DIRECTORY% com/oreilly/aspectjcookbook/MyClass.java
                  jar -cvf MyApp.jar com/oreilly/aspectjcookbook/MyClass.class
              2.ajc -classpath %MY_CLASSPATH% -d %MY_DESTINATION_DIRECTORY% -inpath MyApp.jar com/oreilly/aspectjcookbook/HelloWorld.java
                  -inpath選項強制ajc編譯器從提供的.jar文件中把Java字節(jié)碼提取到-d選項所指定的目錄中。然后,ajc編譯器將把字節(jié)碼在方面織入過程中。
              3. 上述命令并不會產(chǎn)生新的.jar包,如需要將方面織入到新的包中,則需要使用-ourjar選項:
                  ajc -classpath %MY_CLASSPATH% -d %MY_DESTINATION_DIRECTORY% -inpath MyApp.jar -outjar MyAspectOriente的App.jar com/oreilly/aspectjcookbook/HelloWorld.java

          五.其他
            aj命令可以加載時織入方面
            ajdoc則可生成Javadoc文檔

          六. 使用Ant構(gòu)建一個AspectJ項目

          <?xml version="1.0" encoding="utf-8"?>
          <project basedir="." default="compile" name="test">
              
          <property name="src" value="src"/>
              
          <property name="build" value="build"/>
              
          <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
                  
          <classpath>
                      
          <pathelement location="%ASPECTJ_INSTALLATION%/lib/aspectjtools.jar"/>
                  
          </classpath>
              
          </taskdef>
              
          <target name="compile">
                  
          <mkdir dir="${build}"/>
                  
          <iajc destdir="${build}" sourceroots="${src}">
                      
          <classpath>
                          
          <pathelement location="%ASPECTJ_INSTALLATION%/lib/aspectjrt.jar"/>
                      
          </classpath>
                  
          </iajc>
              
          </target>
          </project>

              上述代碼所做的工作:
                1. 使用AspectJ任務(wù)屬性定義了一個新的任務(wù)
                2. 指定aspectjtools.jar的位置
                3. 聲明一個構(gòu)建目標(biāo),他使用iajc任務(wù)來編譯項目,這個任務(wù)反過來又依賴于aspectjrt.jarlai
          posted @ 2008-06-30 23:10 Brian 閱讀(855) | 評論 (0)編輯 收藏

          橫切關(guān)注點
                  面向?qū)ο缶幊痰幕厩疤峋褪亲岄_發(fā)人員能夠在軟件中表述模塊化的橫切關(guān)注點(crosscutting concern)。橫切關(guān)注點是跨軟件特定部分使用的一種行為,通常也是一種數(shù)據(jù)。它可能是一種約束,作為軟件本身的一種特征,或者只是所有類都必須執(zhí)行的一種行為。

          方面
                  方面(aspect)是橫切關(guān)注點的另一種稱呼。方面提供了一種機制,利用該機制,可以用一種模塊化的方式指定橫切關(guān)注點。為了充分利用方面的威力,我們需要了解一些基本概念,以便用一般的方式指定和應(yīng)用方面。我們必須能夠:
                  以模塊化的方式定義方面
                  動態(tài)地應(yīng)用方面
                  根據(jù)一組規(guī)則應(yīng)用方面
                  根據(jù)一種機制和一種環(huán)境,用于指定將為特定方面執(zhí)行的代碼
                  面向方面方法提供了一組語義和語法構(gòu)造來滿足這些要求,使得無論編寫的是哪一類軟件,都可以一般地應(yīng)用方面。這些構(gòu)造就是通知(advice)、連接點(join point)和切入點(pointcut)。

           通知
                  通知就是方面被調(diào)用時所執(zhí)行的代碼。通知包好自身的一組規(guī)則。這組規(guī)則規(guī)定了何時調(diào)用通知,這是與被觸發(fā)的連接點相關(guān)的。

           連接點
                  連接點就是可能會或者可能不會調(diào)用某個通知的應(yīng)用程序內(nèi)的特定點。AspectJ中支持的連接點:
                  被調(diào)用方法時連接
                  在方法執(zhí)行期間連接
                  在調(diào)用構(gòu)造函數(shù)時連接
                  在構(gòu)造函數(shù)執(zhí)行期間連接
                  在方面通知執(zhí)行期間連接
                  在對象初始化以前連接
                  在對象初始化期間連接
                  在靜態(tài)初始化執(zhí)行期間連接
                  在引用類的字段時連接
                  在給類的字段賦值時連接
                  在執(zhí)行處理程序時連接

           切入點
                  切入點是用于聲明連接點中關(guān)注AspectJ機制,用來發(fā)起一份通知。

          public class MyClass
          {
            
          public void foo(int number,String name)
            
          {
              System.out.println(
          "Inside foo(int,String)");
            }


            
          public static void main(String[] args)
            
          {
              
          //Create an instance of MyClass
              MyClass myObject = new MyClass();
              
          //Make the call to foo
              myObject.foo(1 , "Russ Miles");
             }

          }

                  上述類中每一條語句都可看做是潛在的連接點。而下述類中則分別申明了切入點和通知。

          public aspect Some Aspect
          {
            
          //A Pointcut declaration
            pointcut somePointcut():<pointcut logic>;

            
          //A block of Advise
            before:somePointcut()
            
          {
              
          //Do something
            }

          }
          posted @ 2008-06-22 23:34 Brian 閱讀(489) | 評論 (0)編輯 收藏
          一.歸并排序的思路
                  ①把 n 個記錄看成 n 個長度為 l 的有序子表;
                  ②進行兩兩歸并使記錄關(guān)鍵字有序,得到 n/2 個長度為 2 的有序子表; 
                  ③重復(fù)第②步直到所有記錄歸并成一個長度為 n 的有序表為止。
          二.歸并排序算法實例
                  對于歸并排序算法這類的分治算法,其核心就是"分解"和"遞歸求解"。對于"分解"實例,會在下面分析msort()方法中給出。我們先看合并的過程。
                  以下面描述的序列為例,在索引范圍內(nèi)[first , last)的序列還有九個整數(shù)元素,它由索引范圍為[first , mid]的四個元素有序子列表A和索引范圍[mid , last]的五個元素有序子列表B組成。


                  步驟1:比較arr[indexA]=7與arr[indexB]=12。將較小的元素7復(fù)制到數(shù)組tempArr的索引indexC處。并將indexA和indexC都指向下一個位置。


                  步驟2:比較arr[indexA]=10與arr[indexB]=12。將較小的元素10復(fù)制到數(shù)組tempArr的索引indexC處。并將indexA和indexC都指向下一個位置。

                  步驟3:比較arr[indexA]=19與arr[indexB]=12。將較小的元素12復(fù)制到數(shù)組tempArr的索引indexC處。并將indexB和indexC都指向下一個位置。


                  步驟4-7:依次成對比較兩子表的元素將17,19,21,25復(fù)制到數(shù)組tempArr。此時,indexA到達(dá)子表A的未尾(indexA = mid),indexB引用的值為30。

                  步驟8-9:將未到尾部的子表剩余數(shù)據(jù)復(fù)制到tempArr中。

                  步驟10:將tempArr復(fù)制到原始數(shù)據(jù)arr中。

          三.歸并排序算法的實現(xiàn)
              了解了合并過程,那么理解下面的代碼并不是一件難事。下面提供了歸并算法的非泛型版本和泛型版本。
          public class MergeSort {
              
              
          public static void sort(Object[] arr) {
                  
          //create a temporary array to store partitioned elements
                  Object[] tempArr = arr.clone();

                  
          //call msort with arrays arr and tempArr along
                  
          //with the index range
                  msort(arr, tempArr, 0, arr.length);
              }


              
          public static <extends Comparable<? super T>> void sort(T[] arr) {
                  
          //create a temporary aray to store partitioned elements
                  T[] tempArr = (T[]) arr.clone();

                  
          //call msort with arrays arr and tempArr along
                  
          //with the index range
                  msort(arr, tempArr, 0, arr.length);
              }


              
          private static void msort(Object[] arr, Object[] tempArr, int first,
                                        
          int last) {
                  
          //if the sublist has more than 1 element continue
                  if (first + 1 < last) {
                      
          //for sublists of size 2 or more, call msort()
                      
          //for the left and right sublists and than
                      
          //merge the sorted sublists using merge()
                      int midpt = (last + first) / 2;

                      msort(arr, tempArr, first, midpt);
                      msort(arr, tempArr, midpt, last);

                      
          //if list is already sorted, just copy src to
                      
          //dest; this is an optimization that results in faster
                      
          //sorts for nearly ordered lists
                      if (((Comparable) arr[midpt - 1]).compareTo(arr[midpt]) <= 0)
                          
          return;
                      
          //the elements in the ranges [first,mid] and
                      
          //[mid,last] are ordered;merge the ordered sublists
                      
          //into an ordered sequence in the range [first , last]
                      
          //using the temporary array
                      int indexA, indexB, indexC;

                      
          //set indexA to scan sublist A with rang [first , mid]
                      
          //and indexB to scan sublist B with rang [mid , last]
                      indexA = first;
                      indexB 
          = midpt;
                      indexC 
          = first;

                      
          //while both sublists are not exhausted, compare
                      
          //arr[indexA] and arr[indexB]; copy the smaller
                      
          //to tempArr
                      while (indexA < midpt && indexB < last) {
                          
          if (((Comparable) arr[indexA]).compareTo(arr[indexB]) < 0{
                              tempArr[indexC] 
          = arr[indexA]; //copyto tempArr
                              indexA++//increment indexA
                          }
           else {
                              tempArr[indexC] 
          = arr[indexB]; //copyto tempArr
                              indexB++//increment indexB
                          }

                          indexC
          ++//increment indexC
                      }

                      
          //copy the tail of the sublist that is not exhausted
                      while (indexA < midpt) {
                          tempArr[indexC
          ++= arr[indexA++]; //copy to tempArr
                      }
           while (indexB < last) {
                          tempArr[indexC
          ++= arr[indexB++]; //copy to tempArr
                      }

                      
          //copy elements form temporary array to original array
                      for (int i = first; i < last; i++)
                          arr[i] 
          = tempArr[i];
                  }

              }

          }
                  
                  上述代碼中最核心的msort()方法是一遞歸算法。下圖說明了msort()方法中子列表的分割與合并。    

          四.歸并排序算法的效率
                  歸并排序的最壞情況與平均情況運行時間都為O(nlog2n)。假定數(shù)組具有n=2k個元素。如下圖:
                   
                  在層數(shù)0上對msort()方法的第一個調(diào)用會產(chǎn)生兩個遞歸調(diào)用,這兩個遞歸調(diào)用產(chǎn)生長度為n/2的兩個半部分列表,而merge()方法將上述兩個半部分列表組合的一個有序的n元素列表;在層數(shù)1上存在兩個msort()方法的調(diào)用,每個調(diào)用又會產(chǎn)生另外兩個對長度為n/4的列表的遞歸調(diào)用。每個合并會將兩個長度為n/4的子列表連接為一個長度為n/2的有序列表;在層數(shù)2上存在對merge()方法的4=22個調(diào)用,每個調(diào)用會創(chuàng)建一個長度為n/4的有序列表。通常,在層數(shù)i上存在對merge()方法的2i個調(diào)用,每個調(diào)用會創(chuàng)建一個長度為n/2i的有序子列表。
                  層數(shù)0:存在對merge()方法的1=20次調(diào)用。這個調(diào)用對n個元素排序。
                  層數(shù)1:存在對merge()方法的2=21次調(diào)用。這個調(diào)用對n/2個元素排序。
                  層數(shù)2:存在對merge()方法的4=22次調(diào)用。這個調(diào)用對n/4個元素排序。
                  ......
                  層數(shù)i:存在對merge()方法的2i次調(diào)用。這個調(diào)用對n/i個元素排序。
                  在樹中的每一層,合并涉及具有線性運行時間的n/2i個元素,這個線性運行時間需要少于n/2i次的比較。在層數(shù)i上組合的2i個合并操作需要少于2i*n/2i=n次的比較。假定n=2k,分割過程會在n/2k=1的k層數(shù)上終止。那么所有層上完成的工作總量為:k*n = nlog2n。因此msort()方法的最壞情況效率為O(nlog2n)。
          posted @ 2008-06-13 00:54 Brian 閱讀(2319) | 評論 (3)編輯 收藏
          一.插入排序算法的思路
                  
          假定這個數(shù)組的序是排好的,然后從頭往后,如果有數(shù)比當(dāng)前外層元素的值大,則將這個數(shù)的位置往后挪,直到當(dāng)前外層元素的值大于或者等于它前面的位置為止。
          二.插入排序算法實例
                  用五個名字(Monroe,Chin,Flores,Stein和Dare)的列表的插入排序算法為例:
                                                 Monroe    從Monroe開始

                  處理名字Chin        Chine  Monroe    將Chin插入到位置0;Monroe移動至位置1

                  處理名字Flores     Chine  Flores  Monroe    將Flores插入到位置1;Monroe移動至位置2

                  處理名字Stein       Chine  Flores  Monroe  Stein    Stein位置正確 

                  處理名字Dare       Chine  Dare  Flores  Monroe  Stein    將Dare插入在位置1;列表尾部向右移動 

          三.插入排序算法的實現(xiàn)
          public class InsertSort {
              
          //sort an array of elements using insertion sort

              public static <extends Comparable<? super T>> void sort(T[] arr) {
                  
          int i, j, n =
           arr.length;
                  T target;

                  
          /**
                   * place element at index i into the sublist
                   * from index 0 to i-1 where 1<= i,
                   * so it is in the correct positon
                   
          */

                  
          for (i = 1; i < n; i++{
                      
          //
          index j scans down list from index i looking for
                      
          //
          correct position to locate target; assigns it to
                      
          //arr at index j

                      j = i;
                      target 
          =
           arr[i];
                      
          //
          locate insertion point by scanning downward as long
                      
          //
          as target < arr[j] and we have not encountered the
                      
          //beginning of the array

                      while (j > 0 && target.compareTo(arr[j - 1]) < 0{
                          
          //shift elements up list to make room for insertion

                          arr[j] = arr[j - 1];
                          j
          --
          ;
                      }

                      
          //the location is found;insert target
                      arr[j] = target;
                  }

              }

          }

          四.插入排序算法的效率
                  
          假定n是數(shù)組的長度,那么插入排序需要n-1遍。對于通用的遍i來說,插入操作從arr[0]到arr[i-1]的子列表中,并且需要平均i/2次比較。比較的平均總數(shù)為:
                           T(n) = 1/2 + 2/2 + 3/2 + ...... + (n-2)/2 + (n-1)/2 = n(n-1)/4
                  根據(jù)T(n)的主項,插入排序算法的平均運行時間為O(n2)。最好情況為O(n),最壞情況為O(n2)。
          posted @ 2008-06-11 23:56 Brian 閱讀(2700) | 評論 (4)編輯 收藏
          僅列出標(biāo)題
          共5頁: 上一頁 1 2 3 4 5 

          公告


          導(dǎo)航

          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          統(tǒng)計

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          收藏夾

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 通化县| 龙胜| 龙门县| 蚌埠市| 射洪县| 哈尔滨市| 青河县| 北宁市| 黑龙江省| 鄢陵县| 海阳市| 双牌县| 东乌珠穆沁旗| 英德市| 惠东县| 长治县| 犍为县| 新建县| 周至县| 西昌市| 浮山县| 屯昌县| 濉溪县| 十堰市| 新沂市| 小金县| 玛多县| 青岛市| 麻城市| 岗巴县| 灵台县| 同德县| 松江区| 承德市| 西丰县| 金平| 平昌县| 会理县| 河南省| 宽城| 桂东县|