1. 程式人生 > >spring學習(二) ———— AOP之AspectJ框架的使用

spring學習(二) ———— AOP之AspectJ框架的使用

前面講解了spring的特性之一,IOC(控制反轉),因為有了IOC,所以我們都不需要自己new物件了,想要什麼,spring就給什麼。而今天要學習spring的第二個重點,AOP。一篇講解不完,所以這篇文章主要介紹一下什麼是AOP,如何去理解AOP。理解完之後,在spring中如何使用AspectJ AOP框架的。看得懂,寫的出spring配置的那麼就學的差不多了。加油。建議都自己手動實現一遍,這樣才能更好的理解。

                              --WH

一、什麼是AOP?

      AOP:面向切面程式設計,採用橫向抽取機制,取代了傳統的縱向繼承

      IOC:控制反轉     

        跟IOC一樣,我也不知道,這麼高大上的名稱,被嚇壞了,MD,但是通過前面一節的學習,IOC不就是讓spring給我們new物件嗎,而不需要我們自己建立,

        而AOP是一種面向切面的思想,但是我們平常說的spring使用了AOP,實際上說的是spring實現AOP思想的底層原理,而底層原理就是使用動態代理來增強某個方法。所以平常說AOP技術實際上就是指通過動態代理來對方法進行增強。

        比如:我們需要對一個已經寫好的類中的方法進行增強,在不改動該類方法的程式碼的情況下,如何做呢?

        傳統縱向繼承 

          編寫一個類,繼承該類,重寫該類中的這種需要增強的方法,這樣確實可以達到我們的目的,但是一旦需要修改的方法所屬的類不是一個類,那麼就需要在多寫很多子類,增加很多方法,程式設計量就是一個很大的問題,並且後期要修改,工作量也很大。

                

        橫向抽取機制,將要增強所用到的程式碼提取到一個類中,然後對需要增強的方法通過代理類去將其增強即可。

                

              

二、動態代理的兩個方式

      JDK動態代理。介面+實現類

      cglib位元組碼增強。 實現類

      為了更好的理解spring的AOP技術,我們應該手動編寫以上兩種實現動態代理的方法,然後才能體會到spring實現AOP技術所帶來的便利。

 

      2.1、JDK動態代理。

          要使用JDK動態代理的類,必須要有介面。這是前提條件。

                

          編寫UserService介面和UserServiceImpl。 

                  

          建立代理類的工廠proxyFactory

                  

            增強程式碼的類

                  

            測試testApp

                  

            測試結果 成功增強了userServiceImpl物件的add方法。如果別的類有需要被增強的方法,那麼同樣通過建立工廠代理就可以拿到對應的代理物件。然後進行加強

                  

                  

                  

        2.2、cglib動態代理。

            被代理的物件不需要在實現介面,要求就放鬆了很多。很多時候都採用cglib來進行動態代理。

            需要匯入兩個jar包

                  

            spring已經將cglib和asm整合到了spring-core-3.2.0.jar中,所以我們匯入spring的jar包就不需要在重複導這兩個包了。

            跟JDK動態代理的編寫流程是一樣的

            UserServiceImpl。沒有介面了

                  

            增強方法的類

                    

          

            建立代理的工廠(和jdk動態代理有區別)

                      

 

              測試

                   成功增強方法。

              注意:CGLib採用了非常底層的位元組碼技術,其原理是通過位元組碼技術為一個類建立子類,並在子類中採用方法攔截的技術攔截所有父類方法的呼叫,順勢織入橫切邏輯,所以                 說被代理的類不能有final關鍵字 

 

三、spring中使用AOP的相關術語

         3.1、Target:目標類,需要被增強的類,也就是上面我們寫的UserServiceImpl。

         3.2、JointPoint:連線點,目標類上需要被增強的方法,(這些方法可以被增強,也可以不增強,也就是說目標類中所有的方法都可以稱為是連線點)

         3.3、PointCut:切入點,被增強的方法(已經確定這個方法要被增強),切入點就是一個連線點的子集

         3.4、Advice:增強/通知,增強的程式碼,也就是上面將增強的程式碼湊成的一個類。類中的每個方法都代表一個增強的功能程式碼,這個類中的方法就被稱為通知

         3.5、weaving:織入,將切入點和通知結合,從沒被增強到已經增強的過程

         3.6、Aspect:切面,切入點和通知結合,切入點 和 通知點 多點形成面  特殊情況:一個切入點 和 一個通知

                畫張圖就可以理解了。

                

          3.7、Introduction(引介) 特殊的通知,可以對類增強,新增方法或欄位。(知道)

 

四、spring如何幫我們實現AOP技術(初級版)

       spring建立代理工廠bean,屬於半自動,思路跟我們用JDK動態代理和cglib動態代理是一樣的,只是spring通過ioc幫我們建立這些物件,工廠也是由spring提供。唯一的不同是,我們編寫的通知類(之後將其叫成切面類,也就是放增強的程式碼方法的類) 必須實現MethodInterceptor(注意導包時的問題,這個名稱跟cglib中的那個一樣,不要導錯了)介面,並實現invoke方法,這裡就是編寫如何增強切入點,好比上面jdk動態代理和cglib代理中的匿名內部類中的方法一樣。具體下面講解。

       匯入jar包

            

          spring : 4個核心 + 1個依賴

          spring aop聯盟:

          spring aop 實現:

       UserServiceImpl

          

         MySpect 切面類,

            

        applicationcontext.xml。

              

          這裡注意,如果沒有介面,那麼其中必須使用3.4的程式碼也就是34行的程式碼,必須告訴spring,使用cglib進行代理,否則出錯。

         測試

             

    

          總結:這種方式屬性半自動的,需要配置工廠bean,並且目標類的確定太小了,每次只能指定一個目標類,如果我們想對別的類也進行加強,那麼就需要在工廠bean中又配置一個目標類,這就體現不出spring的優勢了。不推薦使用這種。瞭解整個發展過程即可

 

 

五、spring實現AOP技術(中級 掌握)

      全自動過程。直接覆蓋很多目標類,不需要在一個個對目標類進行編寫通知和工廠了。

            其他都一樣,配置檔案不一樣。切入點就不單單是一個目標類了。而是一個範圍。

              

             切面類還是跟上面一樣

              

            測試: 成功

              

          

            總結:相比初級的aop實現,好的地方在不用在自己設定工廠bean了,還在直接大範圍的指定代理目標類,而不是一個類只能被指定一次。這就是全自動,不用我們配置工廠bean

,spring幫我們都做好了。我們只需要關注切面類,也就是通知和切入點的結合即可。

  

六、使用AspectJ框架(xml方式)實現aop(高階,推薦)

        使用這個的好處在於,我們都不需要在切面類中實現什麼通知型別介面了,通知型別介面也在配置檔案中編寫,而切面類只要關注增強的方法程式碼即可。並且不管業務類是否實現介面,編寫的程式碼都是一樣的,如果實現了介面。AspectJ框架會使用jdk代理,如果沒有實現介面,則使用cglib代理,這兩者之間相互轉換。而spring內建的aop技術則需要自己手動去設定,預設是jdk,如果沒有介面,不會自動幫我們轉換。

        導包:新增兩個aspect支援的jar包

             aop聯盟:com.springsource.org.aopalliance-1.0.0.jar

               spring aop支援:spring-aop-3.2.0.RELEASE.jar

               aspect 規範:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

               spring aspect 支援:spring-aspects-3.2.0.RELEASE.jar

              

        AspectJ規定通知型別

          6個,知道5個,掌握一個

            1.before:前置通知(應用:各種校驗)

                   在方法執行前執行,如果通知丟擲異常,阻止方法執行

            2.afterReturning:後置通知(應用:常規資料處理)

                   方法正常返回後執行,如果方法中丟擲異常,通知無法執行

                   必須在方法執行後才執行,所以可以獲得方法的返回值。

            3.around:環繞通知(應用:十分強大,可以做任何事情) 【掌握】

                   方法執行前後分別執行,可以阻止方法的執行。要求必須手動的執行目標方法。

            4.afterThrowing:丟擲異常通知(應用:包裝異常資訊)

                   方法丟擲異常後執行,如果方法沒有丟擲異常,無法執行

            5.after:最終通知(應用:清理現場)

                   方法執行完畢後執行,無論方法中是否出現異常

        配置檔案

            

        通知型別的詳解

            

            

         切面類

            

 

          測試:

              

 

        總結:使用AspectJ框架實現AOP,好處很多,關注的點只有切面類(不需要實現通知型別介面),切入點範圍,還有通知型別。所以在配置檔案中,也只需要配置這三個關鍵的東西即可,具體看上面的配置檔案

 

七、使用AspectJ框架(註解方式)實現aop(高階,推薦)

         使用註解的話,很簡單,就是把xml方式用註解給替代,其中也就做6件事

        1、將切面類配置給spring,相當於<bean id="" class="切面類全限定類名">

           @component

        2、將切面類申明為切面

           @Aspect

            

        3、將目標類配置給spring

           @component  如何不編寫名稱的話,那麼要獲取該物件,則使用userServiceImpl進行獲取。

            

        4、申明目標類切入點範圍

            1.方法必須private,沒有返回值,沒有引數

            2.之後使用將其當成方法呼叫。例如:@After("myPointcut()") 

           @Pointcut("execution(* com.wuhao.aspectj.annotation.*.*(..))")

            

        5、編寫相應的通知           

          @Before 前置

          @AfterReturning  後置,可以獲得返回值,必須在註解中確定返回值引數名稱。

          @AfterThrowing 丟擲異常,可以獲得具體異常資訊,必須在註解確定第二個引數名稱

          @Around 環繞[]

          @After 最終  

            

        

         6:必須在xml中掃描註解和啟用aop

            

        7、測試

            

 

        總結;註解的編寫也很簡單,要會寫註解,首先的知道xml是如何實現的,然後一步步用註解來替代xml的內容即可。並且要知道使用AspectJ框架需要配置哪些內容,就三個點,

           xml:

              目標類bean

              切面類bean   

              <aop:config>

                  <aop:aspect ref="myAspectId">      //切面

                  <aop:pointcut expression="execution(* com.wuhao.aspectj.*.*(..))" id="myPointCutId"/>   //切入點範圍:<aop:pointcut/>   

                  <aop:around method="myAround" pointcut-ref="myPointCutId"/>       //通知型別:<aop:around/>

              </aop:config>

           

              

八、總結

      基本上把spring中使用AOP的技術講清楚了,可能一開始很不習慣,用多了自然就習慣了,並且建議手寫你jdk代理和cglib代理,這樣一步步來,就更容易理解在spring中應用AOP的技術的編寫程式碼了。下一篇還會對spring中使用AOP的技術進一步講解,這一篇相等於寫一個aop的helloworld一樣。