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


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

                              --WZY

一、什么是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一樣。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM