AOP--Aspect Oriented Programming

來源:互聯網
上載者:User

標籤:簽名   res   列印   格式   nim   src   添加   掃描   階段   

1.AOP概念:Aspect Oriented Programming 面向切面編程       Aspect Oriented Programming(AOP)。AOP主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。比如我們最常見的就是日誌記錄了,舉個例子,我們現在提供一個查詢學生資訊的服務,但是我們希望記錄有誰進行了這個查詢。      如果按照傳統的OOP的實現的話,那我們實現了一個查詢學生資訊的服務介面(StudentInfoService)和其實現 類 (StudentInfoServiceImpl.java)同時為了要進行記錄的話,那我們在實作類別(StudentInfoServiceImpl.java)中要添加其實現記錄的過程。這樣的話,假如我們要實現的服務有多個呢?那就要在每個實現的類都添加這些記錄過程。這樣做的話就會有點繁瑣,而且每個實作類別都與記錄服務日誌的行為緊耦合,違反了物件導向的規則【物件導向的設計準則:1、模組化  2、抽象   3、資訊隱藏   4、弱耦合   5、強內聚   6、可重用 】。那麼怎樣才能把記錄服務的行為與業務處理過程中分離出來呢?看起來好像就是查詢學生的服務自己在進行,但卻是背後日誌記錄對這些行為進行記錄,並且查詢學生的服務不知道存在這些記錄過程,這就是我們要討論AOP的目的所在。     AOP的編程,好像就是把我們在某個方面的功能提出來與一批對象進行隔離,這樣與一批對象之間降低了耦合性,可以就某個功能進行編程。 2.作用:本質上來說是一種簡化代碼的方式    繼承機制    封裝方法    動態代理 :BaseMath bean = (BaseMath) ioc.getBean("testmath"); ioc調用實作類別的ID去建立介面的對象,進而調用實作類別實現的方法    …… 3.情景舉例    ①數學計算機介面[MathCalculator]        int add(int i,int j);        int sub(int i,int j);        int mul(int i, int j);        int div(int i,int j);    ②提供簡單實現[EasyImpl]    ③在簡單實現的基礎上讓每一個計算方法都能夠列印日誌[LoginImpl]     ④缺陷        [1]手動添加日誌繁瑣,重複        [2]統一修改不便        [3]對目標方法本來要實現的核心功能有幹擾,使程式碼很臃腫,不易於開發維護     ⑤使用動態代理實現        [1]建立一個類,讓這個類能夠提供一個目標對象的代理對象        [2]在代理對象中列印日誌 4.AOP術語![參見圖例和doc文檔]    AOP概述        ●AOP(Aspect-Oriented Programming,面向切面編程):是一種新的方法論,         是對傳統 OOP(Object-Oriented Programming,物件導向編程)的補充。        ●參見圖例和doc文檔解釋AOP的各個術語!        ●Spring的AOP實現方法:①xml配置的方法                                                ②利用註解的方法    5.在Spring中使用AOP實現日誌功能 :               意思就是在每個函數在執行操作之前都要經過該方法,實現記錄執行資訊的功能        實現過程:    ①Spring中可以使用註解或XML檔案配置的方式實現AOP。    ②匯入jar包 【導包】          com.springsource.net.sf.cglib -2.2.0.jar          com.springsource.org.aopalliance-1.0.0 .jar          com.springsource.org.aspectj.weaver-1.6.8 .RELEASE.jar          commons-logging-1.1.3. jar          spring-aop-4.0.0.RELEASE.jar          spring-aspects-4.0.0.RELEASE.jar          spring-beans-4.0.0.RELEASE.jar          spring-context-4.0.0.RELEASE.jar          spring-core-4.0.0.RELEASE.jar          spring-expression-4.0.0.RELEASE. jar     ③開啟基於註解的AOP功能 ,在此之前也要注意,需要在XML中插入能夠掃描包的代碼 
    <context:component-scan base-package="com.neuedu.aop.mathtest"/> <!-- 掃描包的代碼 -->    <aop:aspectj-autoproxy/>   <!-- 開啟註解aop功能  -->
            ④聲明一個切面類,並把這個切面類加入到IOC容器中
        @Aspect//表示這是一個切面類        @Component//加入IOC容器        public class LogAspect {}
     ⑤在切面類中聲明通知方法        [1]前置通知:@Before        [2]返回通知:@AfterReturning        [3]異常通知:@AfterThrowing        [4]後置通知:@After        [5]環繞通知:@Around :環繞通知是前面四個通知的集合體!       
  @Aspect//表示這是一個切面類        @Component//將本類對象加入到IOC容器中!         public class LogAspect {            @Before(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")            public void showBeginLog(){                System.out.println("AOP日誌開始");            }            @After(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")            public void showReturnLog(){                System.out.println("AOP方法返回");            }            @AfterThrowing(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")            public void showExceptionLog(){                System.out.println("AOP方法異常");            }            @AfterReturning(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")            public void showAfterLog(){                System.out.println("AOP方法結束");            }        }
   ⑥被代理的對象也需要加入IOC容器       
 @Component//加入IOC容器        public class MathCalculatorImpl {             public int add(int i,int j){                int result = i+j;                return result;            }            public int sub(int i,int j){                int result = i-j;                return result;            }            public int multi(int i,int j){                int result = i*j;                return result;            }            public int divide(int i,int j){                int result = i/j;                return result;            }        }

  

6.切入點運算式:   1.上述案例通過junit測試,會發現,我們調用目標類的四個方法只有add方法被加入了4個通知,如果想所有的方法都加上這些通知,可以      在切入點運算式處,將execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int)) 換成:                          execution(public int com.neuedu.aop.target.MathCalculatorImpl.*(int, int))這樣只要是有兩個參數,且      參數類型為int的方法在執行的時候都會執行其相應的通知方法!    2.①切入點運算式的文法格式         execution([許可權修飾符] [傳回值類型] [簡單類名/全類名] [方法名]([參數列表]))       1.任意參數,任意類型      2.任意傳回值      3.用@PointCut註解統一聲明,然後在其它通知中引用該統一聲明即可!             需要注意的是:許可權是不支援寫萬用字元的,當然你可以寫一個*表示所有許可權所有傳回值!       最詳細的切入點運算式:        execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))      最模糊的切入點運算式:         execution (* *.*(..)) 7.統一聲明切入點運算式 
     @Pointcut(value= "execution(public int com.atguigu.aop.target.EazyImpl.add(int,int))")     public void myPointCut(){}     //調用上面的函數,就可以代替重複的很多代碼@AfterReturning (value="myPointCut()", returning= "result")

  

8.通知方法的細節    ①在通知中擷取目標方法的方法名和參數列表        [1]在通知方法中聲明一個JoinPoint類型的形參        [2]調用JoinPoint對象的getSignature()方法擷取目標方法的簽名        [3]調用JoinPoint對象的getArgs()方法擷取目標方法的實際參數列表     ②在返回通知中擷取方法的傳回值        [1]在@AfterReturning註解中添加returning屬性           
 @AfterReturning (value="myPointCut()", returning= "result")

 

        [2]在返回通知的通知方法中聲明一個形參,形參名和returning屬性的值一致          
showReturnLog(JoinPoint joinPoint, Object result)

  

    ③在異常通知中擷取異常對象        [1]在@ AfterThrowing註解中添加throwing屬性        
 @AfterThrowing (value="myPointCut()",throwing= "throwable" )
         [2]在異常通知的通知方法中聲明一個形參,形參名和throwing屬性值一致           
showExceptinLog(JoinPoint joinPoint, Throwable throwable)
 9.根據介面類型擷取target對象時,實際上真正放在IOC容器中的對象是代理對象,而並不是目標對象本身!  10.環繞通知:@Around    1.環繞通知需要在方法的參數中指定JoinPoint的子介面類型ProceedingJoinPoint為參數   
     @Around(value="pointCut()")        public void around(ProceedingJoinPoint joinPoint){        }

 

    2.環繞通知會將其他4個通知能乾的,自己都給幹了!        注意:@Around修飾的方法一定要將方法的傳回值返回!本身相當於代理! 
     @Around(value="pointCut()")        public Object around(ProceedingJoinPoint joinPoint){            Object[] args = joinPoint.getArgs();            Signature signature = joinPoint.getSignature();            String methodName = signature.getName();            List<Object> list = Arrays.asList(args);            Object result = null;            try {                //目標方法之前要執行的操作                System.out.println("[環繞日誌]"+methodName+"開始了,參數為:"+list);                //調用目標方法                result = joinPoint.proceed(args);                 //目標方法正常執行之後的操作                System.out.println("[環繞日誌]"+methodName+"返回了,傳回值為:"+result);            } catch (Throwable e) {                //目標方法拋出異常資訊之後的操作                System.out.println("[環繞日誌]"+methodName+"出異常了,異常對象為:"+e);                throw new RuntimeException(e.getMessage());            }finally{                //方法最終結束時執行的操作!                System.out.println("[環繞日誌]"+methodName+"結束了!");            }            return result;        } 

  

11.切面的優先順序    對於同一個代理對象,可以同時有多個切面共同對它進行代理。    可以在切面類上通過@Order (value=50)註解來進行設定,值越小優先順序越高! 
   @Aspect        @Component        @Order(value=40)        public class TxAspect {            @Around(value="execution(public * com.neuedu.aop.target.MathCalculatorImpl.*(..))")            public Object around(ProceedingJoinPoint joinPoint){                Object[] args = joinPoint.getArgs();                Signature signature = joinPoint.getSignature();                String methodName = signature.getName();                List<Object> list = Arrays.asList(args);                Object result = null;                try {                    //目標方法之前要執行的操作                    System.out.println("[交易記錄]"+methodName+"開始了,參數為:"+list);                    //調用目標方法                    result = joinPoint.proceed(args);                     //目標方法正常執行之後的操作                    System.out.println("[交易記錄]"+methodName+"返回了,傳回值為:"+result);                } catch (Throwable e) {                    //目標方法拋出異常資訊之後的操作                    System.out.println("[交易記錄]"+methodName+"出異常了,異常對象為:"+e);                    throw new RuntimeException(e.getMessage());                }finally{                    //方法最終結束時執行的操作!                    System.out.println("[交易記錄]"+methodName+"結束了!");                }                return result;            }        }
 12.注意:上面的AOP都是通過註解實現的,AOP實際上也可以通過xml配置的方式實現!    
<!-- 1.將需要載入到IOC容器中的bean配置好 -->    <bean id="logAspect" class="com.neuedu.aop.proxy.LogAspect"></bean>    <bean id="txAspect" class="com.neuedu.aop.target.TxAspect"></bean>    <bean id="calculator" class="com.neuedu.aop.target.MathCalculatorImpl"></bean>     <!-- 2.配置AOP,需要匯入AOP名稱空間 -->    <aop:config>       <!-- 聲明切入點運算式 -->       <aop:pointcut expression="execution(* com.neuedu.aop.target.MathCalculatorImpl.*(..))" id="myPointCut"/>       <!-- 配置日誌切面類,引用前面的類 ,通過order屬性控制優先順序-->       <aop:aspect ref="logAspect" order="25">               <!-- 通過method屬性指定切面類的切面方法,通過pointcut-ref指定切入點運算式 -->               <aop:before method="showBeginLog" pointcut-ref="myPointCut"/>               <aop:after method="showAfterLog" pointcut-ref="myPointCut"/>               <aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" throwing="ex"/>               <aop:after-returning method="showReturnLog" pointcut-ref="myPointCut" returning="result"/>               <aop:around method="around" pointcut-ref="myPointCut"/>       </aop:aspect>               <!-- 配置事務切面類,引用前面的類 -->       <aop:aspect ref="txAspect" order="20">               <aop:around method="around" pointcut-ref="myPointCut"/>       </aop:aspect>    </aop:config>

 

    需要知道的是:事務的管理是和AOP是有很大關係的,即聲明式事務的底層是用事務實現的!

AOP--Aspect Oriented Programming

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.