1. 程式人生 > >Spring aop 實例(轉)

Spring aop 實例(轉)

插入 transacti etag onf ans 結果 service actor package

  面向切面編程,有效的降低了代碼之間的耦合性,易於維護;例如:我們習慣在代碼中加上一些日誌信息,在程序出錯時方便快速查找找到問題,通常做法是在請求進入方法的時候打印日誌,退出前打印日誌,還有在出錯時打印日誌,那麽問題就來了,每個方法中都需要打印日誌,這些相同的部分就可以當做一個切面,通過配置切點來觸發所需要的功能,比如,我需要在請求進入方法的時候打印,即可使用aop當中的前置通知來做到,這樣就不需要每個方法中都去寫一遍,配置好之後引用即可。

  簡單的記錄一下spring aop的一個示例

  基於兩種配置方式:

      1:基於xml配置

      2:基於註解配置

  這個例子是模擬對數據庫的更改操作添加事物

  其實並沒有添加,只是簡單的輸出了一下記錄

  首先看下整個例子的目錄圖

  技術分享圖片

全部代碼就不貼了,數目有點多,不過很簡單,看一部分就能夠明白

第一種配置方式

  基於xml方式配置

  首先將service,dao註冊到spring容器

  技術分享圖片

  配置一下掃描包還是很方便的

  接下來看下service 

技術分享圖片
 1 package com.yangxin.core.service.impl;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Service;
 5 
 6 import com.yangxin.core.dao.UserDao;
 7 import com.yangxin.core.pojo.User;
 8 import com.yangxin.core.service.UserService;
 9 
10 @Service
11 public class UserServiceImpl implements UserService {
12 
13     @Autowired
14     private UserDao userDao;
15     
16     @Override
17     public void addUser(User user) {
18         userDao.insertUser(user);
19         System.out.println("添加成功");
20     }
21 
22     @Override
23     public void deleteUser(String name) {
24         userDao.deteleUser(name);
25         System.out.println("刪除成功");
26     }
27 
28 }
技術分享圖片

要做的事情很簡單,插入一條數據,刪除一條數據

接下來看下切面代碼

技術分享圖片
 1 package com.yangxin.core.transaction;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 
 5 import com.yangxin.core.pojo.User;
 6 
 7 public class TransactionDemo {
 8     
 9     //前置通知
10     public void startTransaction(){
11         System.out.println("begin transaction ");
12     }
13     
14     //後置通知
15     public void commitTransaction(){
16         System.out.println("commit transaction ");
17     }
18     
19     //環繞通知
20     public void around(ProceedingJoinPoint joinPoint) throws Throwable{
21         System.out.println("begin transaction");
22         //調用process()方法才會真正的執行實際被代理的方法
23         joinPoint.proceed();
24         
25         System.out.println("commit transaction");
26     }
27     
28 }
技術分享圖片

然後看下這個切面在applicationContext.xml中是如何配置的

技術分享圖片

技術分享圖片
 1 <aop:config>
 2         <aop:pointcut expression="execution(* com.yangxin.core.service.*.*.*(..))" id="p1" />
 3 
 4         <aop:aspect ref = "transactionDemo">
 5         
 6         <aop:before method="startTransaction" pointcut-ref="p1" />
 7         
 8         <aop:after-returning method="commitTransaction" pointcut-ref="p1"/>
 9         
10         </aop:aspect>
11     </aop:config>
技術分享圖片

這裏沒有演示環繞通知

好了,運行測試代碼

測試代碼如下

技術分享圖片
 1   @Test
 2     public void test1(){
 3         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
 4         
 5         UserService userService = applicationContext.getBean(UserService.class);
 6         
 7         User user = new User();
 8         
 9         user.setAge(19);
10         user.setName("yangxin");
11                 
12         userService.addUser(user);
13         userService.deteleUser("yangxin");
1415         
16     }
技術分享圖片

控制臺輸出如下

  begin transaction

  添加成功

  commit transaction

  begin transaction

  刪除成功

  commit transaction

現在來測試一下環繞通知

修改一下applicationContext.xml中的配置切面那一部分

修改後的代碼

技術分享圖片
1 <aop:config>
2         <aop:pointcut expression="execution(* com.yangxin.core.service.*.*.*(..))" id="p1" />
3 
4         <aop:aspect ref = "transactionDemo">
5         
6         <aop:around method="around" pointcut-ref="p1"/>
7         
8         </aop:aspect>
9     </aop:config>
技術分享圖片

運行測試代碼

輸出如下

begin transaction
添加成功
commit transaction
begin transaction
刪除成功
commit transaction

好了,現在貼下如何用註解的方法

貼下基於註解的切面的代碼

技術分享圖片
 1 package com.yangxin.core.transaction;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.AfterReturning;
 5 import org.aspectj.lang.annotation.Around;
 6 import org.aspectj.lang.annotation.Aspect;
 7 import org.aspectj.lang.annotation.Before;
 8 import org.aspectj.lang.annotation.Pointcut;
 9 
10 @Aspect
11 public class TransactionDemo2 {
12     
13     @Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
14     public void point(){
15         
16     }
17     
18     @Before(value="point()")
19     public void before(){
20         System.out.println("transaction begin");
21     }
22     
23     @AfterReturning(value = "point()")
24     public void after(){
25         System.out.println("transaction commit");
26     }
27     
28     @Around("point()")
29     public void around(ProceedingJoinPoint joinPoint) throws Throwable{
30         System.out.println("transaction begin");
31         joinPoint.proceed();
32         System.out.println("transaction commit");
33         
34     }
35 }
技術分享圖片

在applicationContext.xml中配置

1 <bean id = "transactionDemo2" class = "com.yangxin.core.transaction.TransactionDemo2" />
1 <aop:aspectj-autoproxy />

測試步驟和以上一致,這裏就不貼了

結合例子我們來看看這些核心的概念:

  2.1、切面(Aspect):是一個類,裏面定義了通知與切點。

  2.2、切點(PointCut):表達式。就是告訴程序要在執行哪些核心業務的時候,執行非核心的業務。

  2.3、通知(advice):五種通知方式:

    • @Before:前置通知,在調用目標方法之前執行通知定義的任務
    • @After:後置通知,在目標方法執行結束後,無論執行結果如何都執行通知定義的任務
    • @After-returning:後置通知,在目標方法執行結束後,如果執行成功,則執行通知定義的任務
    • @After-throwing:異常通知,如果目標方法執行過程中拋出異常,則執行通知定義的任務
    • @Around:環繞通知,在目標方法執行前和執行後,都需要執行通知定義的任務。

Spring aop 實例(轉)