spring筆記--使用springAPI實現AOP的一個簡單例子

来源:http://www.cnblogs.com/fingerboy/archive/2016/03/14/5275928.html
-Advertisement-
Play Games

Spring的另一個重要思想是AOP,面向切麵的編程,它提供了一種機制,可以在執行業務前後執行另外的代碼,Servlet中的Filter就是一種AOP思想的體現,下麵通過一個例子來感受一下. 假設我們現在需要在針對資料庫進行CRUD操作時添加一組日誌,即在執行CRUD方法前後分別加上一句話,實現簡單


  Spring的另一個重要思想是AOP,面向切麵的編程,它提供了一種機制,可以在執行業務前後執行另外的代碼,Servlet中的Filter就是一種AOP思想的體現,下麵通過一個例子來感受一下.

  假設我們現在需要在針對資料庫進行CRUD操作時添加一組日誌,即在執行CRUD方法前後分別加上一句話,實現簡單的面向切麵編程的功能.我用到的是spring4,在配置文件上較之之前的版本可能有些不同.

  使用springAPI來實現AOP,除了spring必不可少的核心jar包,還需要兩個jar包需要導入:

    1.   aspectjweaver.jar   下載鏈接: http://download.csdn.net/detail/luojiming1990/5432831
    2.   aopalliance.jar    下載鏈接:http://download.csdn.net/detail/zhaoshe/3153090

  並且配置文件的頭文件也需要略作修改,詳見下麵實例中的beans.xml.

  UserService類(省略資料庫操作代碼,只做簡單的列印來模擬):

public class UserService {

    public void add(){
        System.out.println("添加用戶");
    }
    public void delete(){
        System.out.println("刪除用戶");
    }
    public void update(){
        System.out.println("修改用戶");
    }
    public void search(){
        System.out.println("查詢用戶");
    }
}

Log類(在執行增刪改查方法前執行):

public class Log  implements MethodBeforeAdvice{

    /***
     * method:被調用的方法對象
     * arg1:被調用的方法的參數
     * target:被調用方法的目標對象 
     */
    @Override
    public void before(Method method, Object[] arg1, Object target)
            throws Throwable {
        System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被執行");
    }

}

AfterLog類(在執行增刪改查方法後執行):

public class AfterLog implements AfterReturningAdvice{
    /**
     * returnValue:返回值類型
     * method:被調用的方法對象
     * arg1:被調用的方法的參數
     * target:被調用方法的目標對象 
     */
    @Override
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
        
        System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被執行成功,返回值是"+returnValue);
        
 }

spring配置文件(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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="userService" class="com.wang.service.UserService"></bean>
    <bean id="log" class="com.wang.log.Log"></bean>
    <bean id="afterlog" class="com.wang.log.AfterLog"></bean>
    <aop:config>
    <!--"*"為通配符表示所有方法,第一個* 表示任意返回值 第二個*表示所有方法      
        ".."表示任意個數的參數 -->
        <aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>
           <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
           <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

測試代碼testDemo:

   @Test
    public void test1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
        UserService userService=(UserService)context.getBean("userService");
        userService.add();
        userService.search();
    }

運行測試可以看到控制台的列印結果:

com.wang.service.UserService中的add方法被執行
添加用戶
com.wang.service.UserService中的add方法被執行成功,返回值是null

com.wang.service.UserService中的search方法被執行
查詢用戶
com.wang.service.UserService中的search方法被執行成功,返回值是null

在配置文件中,我們看到了一些這樣的代碼:

 <aop:config>
    <!--"*"為通配符表示所有方法      
        ".."表示任意個數的參數 -->
        <aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>
           <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
           <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
    </aop:config>

我們來介紹幾個AOP的相關概念,這個就比較好理解了:

  • 切麵(Aspect):在本例中.add(),delete(),等方法中都有一些代碼,在真實的程式中這裡不會只是簡單的列印語句而是一些有意義的代碼,這些代碼可以看做是AOP的切麵.
  • 通知(Advisor):本例中的兩個日誌類,這裡可以成為攔截器,都是實現了某個*Advisor介面,這兩個類就是指AOP中的通知,一旦Spring符合了條件,就會發出通知,與生活中我們所說的通知不同的是,Spring中的通知是帶有執行代碼的,能實現某種功能.
  • 切入點(pointcut):在配置攔截器(<aop-config>)的時候,xml中配置了UserService中所有的方法都是用攔截器,這個配置是通過spring中的一個已經寫好的類完成的,這個類能配置對哪些方法使用攔截器,從那個地方"切入"進去.配置是可以使用通配符.

簡而言之:"切入點"負責往"什麼地方"插入代碼,"通知"負責插入"什麼代碼".

 

  SpringAOP將公共的業務(如日誌,安全)和領域業務結合,當執行領域業務時候把公共業務加進來,實現公共業務的重覆利用,使得領域業務功能更加純粹,程式員可以專註於領域業務.

  當然除了使用springAPI,我們也可以通過自定義的類,即不需要實現任何藉口或繼承任何類,的方式來實現上述功能:

  只需要一個Log類:

public class Log  {

    public void before(){
        System.out.println("執行方法前");
    }
    
    public void after(){
        System.out.println("執行方法後");
    }
}

修改配置文件beans.xml中的<aop-config>為:

    <aop:config>
           <aop:aspect ref="log">
           <aop:pointcut expression="execution(* com.wang.service.UserService.*(..))" id="pointcut"/>
               <aop:before method="before" pointcut-ref="pointcut"/>
               <aop:after method="after" pointcut-ref="pointcut"/>
           </aop:aspect>
       </aop:config>

執行上面的測試代碼,列印出的結果是:

執行方法前
添加用戶
執行方法後
執行方法前
查詢用戶
執行方法後

 其實這種配置方式還可以用註解來完成,下麵介紹一下使用註解的方式,順帶講一個環繞方法,它和before和after一樣,不過是在某一個方法前後都會執行的代碼:

  Log類:

@Aspect
public class Log  {
    @Before("execution(* com.wang.service.*.*(..))")
    public void before(){
        System.out.println("執行方法前");
    }
    @After("execution(* com.wang.service.*.*(..))")
    public void after(){
        System.out.println("執行方法後");
    }
    
    @Around("execution(* com.wang.service.*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("環繞前");
        System.out.println("簽名:"+pjp.getSignature());
        //執行目標方法
        Object proceed = pjp.proceed();
        System.out.println("環繞後");
        return proceed;
    }

在beans.xml中,只需要將<aop-config>修改為一行代碼:

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="userService" class="com.wang.service.UserService"></bean>
    <bean id="log" class="com.wang.log.Log"></bean>
    <aop:aspectj-autoproxy/>
</beans>

列印結果如下,讀者自行理解,這裡對於around不再解釋:

環繞前
簽名:void com.wang.service.UserService.add()
執行方法前
添加用戶
環繞後
執行方法後


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

-Advertisement-
Play Games
更多相關文章
  • 最近實習期間負責了公司某個項目的一個功能模塊裡面的word導出功能,使用的是ASPOSE.WORD類庫,但是經常導出時候會遇到圖中的問題,大概意思就是兩個表格不能跨在一起,調試了好幾次還是沒發現具體的原因,但是有一個小技巧可以避免。就是在出現問題的結束域和開始域之間加個一個換行,就是回車,問題就解決
  •   大致是:var products = db.Products.Select(new ProductVm{Name=SomeMethod() });針對IQueryable集合的查詢操作會被LINQ Provider編譯成SQL語句,此時,是無法識別方法的。解決辦法:把數據放到記憶體中,再調用方法v
  • HashMap對於做Java的小伙伴來說太熟悉了。估計你們每天都在使用它。它為什麼叫做HashMap?它的內部是怎麼實現的呢?為什麼我們使用的時候很多情況都是用String作為它的key呢?帶著這些疑問讓我們來瞭解HashMap! HashMap是一個用”KEY”-“VALUE”來實現數據存儲的類。
  • php獲取POST數據的三種方法php 圖片加水印源代碼php+ajax+json的一個最簡單實例php 漢字轉拼音源碼php遍歷目錄,生成目錄下每個文件的md5值並寫入到結果文件中php實現linux命令tail -fphp json_encode與json_decode使用實例php curl
  • Tcp通信過程一般為如下步驟: 伺服器綁定埠,等待客戶端連接。 客戶端通過伺服器的ip和伺服器綁定的埠連接伺服器。 伺服器和客戶端通過網路建立一條數據通路,通過這條數據通路進行數據交互。 常用API: 1. ACE_INET_Addr類。 ACE"地址"類ACE_Addr的子類,表示TCP/IP
  • 面向對象編程的基本原則:  1、設置類的屬性 用以上方法設置屬性值會有很多問題: 第一:PHP允許動態設置屬性,如果拼錯或忘記屬性名時並不會得到警告。例如錯誤地把 寫作 ,當我們輸出作者名字的時候,會有意想不到的結果。 第二:類太過鬆散,我們沒有強制設置標題、價格或者產品名稱,客戶端代碼可以確定的是
  •   電源如同人類的迴圈系統,是能源輸入輸出的地方,若是電源設計不合理,或者能量輸出不足,帶給整個電子系統都是致命的。   對於線性電源來說,有些概念必須要註意,最大功耗 PD = | Vin - Vout | x Iout;熱阻是指熱量從器件的晶片上向外傳導時受到的阻力,其單位是℃/W。那麼熱阻和最
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...