Spring(三)__aop編程

来源:http://www.cnblogs.com/xiangkejin/archive/2016/11/15/6065181.html
-Advertisement-
Play Games

aop( aspect oriented programming ) 面向切麵編程,是對所有對象或者是一類對象編程 幾個重要的概念: 1.切麵(aspect):要實現的交叉功能,是系統模塊化的一個切麵或領域。如日誌記錄。 2.連接點:應用程式執行過程中插入切麵的地點,可以是方法調用,異常拋出,或者要 ...


aop( aspect oriented programming )

 

面向切麵編程,對所有對象或者是一類對象編程

 

幾個重要的概念:

1.切麵(aspect):要實現的交叉功能,是系統模塊化的一個切麵或領域。如日誌記錄。

2.連接點:應用程式執行過程中插入切麵的地點,可以是方法調用,異常拋出,或者要修改的 欄位。

3.通知:切麵的實際實現,他通知系統新的行為。如在日誌通知包含了實 現日誌功能的代碼,如嚮日志文件寫日誌。通知在連接點插入到應用系統中。

4.切入點:定義了通知應該應用在哪些連接點,通知可以應用到AOP框架支持的任何連接點。

5.引入:為類添加新方法和屬性。

6.目標對象:被通知的對象。既可以是你編寫的類也可以是第三方類。

7.代理:將通知應用到目標對象後創建的對象,應用系統的其他部分不用為了支持代理對象而 改變。

8.織入:將切麵應用到目標對象從而創建一個新代理對象的過程。織入是一個過程。織入發生在目標 對象生命周期的多個點上:

編譯期:切麵在目標對象編譯時織入.這需要一個特殊的編譯器.

類裝載期:切麵在目標對象被載入JVM時織入.這需要一個特殊的類載入器.

運行期:切麵在應用系統運行時織入.

 

創建切麵的方式:

還有一種引用通知方式。總共五種類型,下麵一一舉例實現:

編程說明:

步驟:

1.定義介面

2.編寫對象(被代理對象=目標對象)

3.編寫通知(前置通知目標方法調用前調用)

4.在beans.xml文件配置

4.1 配置 被代理對象=目標對象

4.2 配置通知

4.3 配置代理對象 ProxyFactoryBean的對象實例

4.3.1 代理介面集

4.3.2 織入通知

4.3.3 配置被代理對象

 

一.定義介面:

介面1:

public interface TestServiceInter {

    public void sayHello();
}

介面2:

public interface TestServiceInter2 {

    public void sayBye();
}

 

二、編寫對象

public class Test1Service implements TestServiceInter,TestServiceInter2 {
    private String name;    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void sayHello() {
        System.out.println("hi "+name);
    }
    public void sayBye() {
        System.out.println("bye "+name);
        //int i=9/0;
    }
}

 

三、編寫通知

1.前置通知

public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
    /**
     * method: 被調用方法名字
     * args: 給method傳遞的參數
     * target: 目標對象
     */
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        System.out.println("..............");
        System.out.println("記錄日誌..."+method.getName());
    }
}

該介面提供了獲得目標方法、參數和目標對象的機會。不能夠改變運行時參數,即不能替換參數對象和目標對象。

註意在方法結束後不返回任何值。原因是該介面返回後,目標方法將會被調用,應該返回目標對象的返回值。

該介面唯一能 阻止目標方法被調用的途徑是拋出異常或(System.exit())。

 

2.後置通知

與前置通知類似

public class MyAfterReturningAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable       
        System.out.println("關閉資源。。。。");
    }
}

 

3.環繞通知

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        
        System.out.println("調用方法前。。。");
        Object obj=arg0.proceed();       //目標對象方法的調用執行
        System.out.println("調用方法後。。。");
        return obj;
    }
}

該介面同前兩種通知有兩個重要區別:

1.該通知能夠控制目標方法 是否真的被調用。通過invocation.proceed()方法來調用。

2.該通知可以控制返回的對象。可以返回一個與proceed()方法返回對象完全不同的對象。但要謹慎使用。

 

4.異常通知

public class MyThrowsAdvice implements ThrowsAdvice {
    
    public void afterThrowing(Method m,Object[] os,Object target,Exception throwable){
        System.out.println("出大事了"+throwable.getMessage());
    }

}

public interface ThrowsAdvice{

}

該介面為標識性介面,沒有任何方法,但實現該介面的類必須要有如下形式的方法:

public void afterThrowing(Throwable throwable);

public void afterThrowing(Method m,Object[] os,Object target,Exception throwable);

第一個方法只接受一個參數:需要拋出的異常。 第二個方法接受異常、被調用的方法、參數以及目標對象。

 

 5.引入通知

如果不能表達在應用系統的什麼地方應用 通知的話,通知將毫無用處,這就是切入點的用處。

切入點決定了一個特定的類的特定方法是否滿足一定的規則。若符合,通知就應用到該方法上。

引入通知只需要在beans.xml中自定義切入點來控制通知。

 

四、beans.xml配置

beans.xml

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
                >

<!-- 配置被代理的對象 -->
<bean id="test1Service" class="com.hsp.aop.Test1Service">
<property name="name" value="順平" />
</bean>

<!-- 配置前置通知 -->
<bean id="MyMethodBeforeAdvice" class="com.hsp.aop.MyMethodBeforeAdvice" /> 
<!-- 配置後置通知 -->
<bean id="myAfterReturningAdvice" class="com.hsp.aop.MyAfterReturningAdvice"/>
<!-- 配置環繞通知 -->
<bean id="myMethodInterceptor" class="com.hsp.aop.MyMethodInterceptor" />
<!-- 配置異常通知 -->
<bean id="myThrowsAdvice" class="com.hsp.aop.MyThrowsAdvice"/>
<!-- 定義前置通知的切入點 -->
<bean id="myMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" >
  <property name="advice" ref="MyMethodBeforeAdvice" />
  <property name="mappedNames">
  <list>
  <value>sayHello</value>
  </list>
  </property>
</bean>

<!-- 代理對象的實現原理.實現介面

    proxyFactoryBean implements TestServiceInter,TestServiceInter2{
        public void sayHello();
    }
    
    思考:多態下介面類型的轉換
    interface Inter1{};
    class A implements Inter1,Inter2{
    }
    Inter1 a=new A();
    Inter2 b=(Inter2)a;
-->


<!-- 配置代理對象,只需配置而不要寫 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理介面集   這裡name值是固定的-->
<property name="proxyInterfaces">
    <list>
        <value>com.hsp.aop.TestServiceInter</value>
        <value>com.hsp.aop.TestServiceInter2</value>
    </list>
</property>

<!-- 把通知織入到代理對象 這裡name值是固定的  -->
<property name="interceptorNames">
    <list>
    <!-- 相當於把MyMethodBeforeAdvice前置通知和代理對象關聯,我們也
    可以把通知看成攔截器,struts2核心攔截器 -->    
    <!-- 相當於自定義切入點來控制前置通知的使用 -->
    <value>myMethodBeforeAdviceFilter</value>
    <!-- 織入後置通知 -->
    <value>myAfterReturningAdvice</value>
    <!-- 織入環繞通知 -->
    <value>myMethodInterceptor</value>
    <!-- 織入異常通知 -->
    <value>myThrowsAdvice</value>
    </list>
</property>

<!-- 配置被代理對象,可以指定 -->
<property name="target" ref="test1Service"/>
</bean>

</beans>

測試:

public static void main(String[] args) {        

        ApplicationContext ac=new ClassPathXmlApplicationContext("com/hsp/aop/beans.xml");
        TestServiceInter ts=(TestServiceInter) ac.getBean("proxyFactoryBean");    
        ts.sayHello();
        ((TestServiceInter2)ts).sayBye();                    
    }

執行結果:

現在加入列印代理對象的類型的語句:

public static void main(String[] args) {        

        ApplicationContext ac=new ClassPathXmlApplicationContext("com/hsp/aop/beans.xml");
        TestServiceInter ts=(TestServiceInter) ac.getBean("proxyFactoryBean");    
        System.out.println("ts的類型是"+ts);
        ts.sayHello();
        ((TestServiceInter2)ts).sayBye();                    
    }

執行結果:

ts是個代理對象,從中還可以看出只要代理對象被調用就會執行織入通知。

提問? springaop中,當你通過代理對象去實現aop的時候,獲取的ProxyFactoryBean是什麼類型?

: 返回的是一個代理對象,如果目標對象實現了介面,則spring使用jdk 動態代理技術,如果目標對象沒有實現介面,則spring使用CGLIB技術.

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在網上找了很多方法,終於找到了一個,記錄之。 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(Service1Soap.class);// 設置請求介面 factory.setA... ...
  • 1、錯誤類型:PHP致命錯誤 Error type: PHP Fatal error Fatal error: Cannot redeclare (a) (previously declared in (b)) in (c) on line (d) 2、錯誤描述: 該錯誤報告表示你正企圖對已經定義過 ...
  • urllib requets selenium的應用場景 cookie識別用戶身份和記錄用戶狀態 driver.get_cookies() 獲得cookie信息 add_cookie(cookie_dict) 向cookie添加會話信息 delete_cookie(name) 刪除特定(部分)的co ...
  • 上篇說到了 RabbitMQ 的安裝。 這次要在講案例之前,需要安裝PHP的AMQP擴展。不然可能會報以下兩個錯誤。 1.Fatal error: Class 'AMQPConnection' not found 2. Fatal error: Uncaught exception 'AMQPCon ...
  • RabbitMQ: 1、是實現AMQP(高級消息隊列協議)的消息中間件的一種。 2、主要是為了實現系統之間的雙向解耦而實現的。當生產者大量產生數據時,消費者無法快速消費,那麼需要一個中間層。保存這個數據。 一般提到 RabbitMQ 和消息,都會用到以下一些專有名詞: (1)生產(Producing ...
  • 閱讀目錄 前言 怎麼賣 領域服務的使用 回到現實 結語 閱讀目錄 前言 怎麼賣 領域服務的使用 回到現實 結語 一、前言 上篇中我們講述了“把商品賣給用戶”中的商品和用戶的初步設計。現在把剩餘的“賣”這個動作給做了。這裡提醒一下,正常情況下,我們的每一步業務設計都需要和領域專家進行溝通,儘可能的符合 ...
  • 一、概述 迭代器模式提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露其內部的表示。 二、解決問題 迭代器模式就是提供一種遍歷元素的統一介面,用一致的方法遍歷聚合元素。試想,如果我們的聚合元素是用不同的方式實現的,有些用了數組,有些用了java的集合類,或者還有其他方式,當客戶端要遍歷這些元素 ...
  • 原文地址 序列圖主要用於展示對象之間交互的順序。 序列圖將交互關係表示為一個二維圖。縱向是時間軸,時間沿豎線向下延伸。橫向軸代表了在協作中各獨立對象的類元角色。類元角色用生命線表示。當對象存在時,角色用一條虛線表示,當對象的過程處於激活狀態時,生命線是一個雙道線。 消息用從一個對象的生命線到另一個對 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...