Spring aop 實例(轉)


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

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

  基於兩種配置方式:

      1:基於xml配置

      2:基於注解配置

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

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

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

  

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

第一種配置方式

  基於xml方式配置

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

  

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

  接下來看下service 

package com.yangxin.core.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yangxin.core.dao.UserDao;
import com.yangxin.core.pojo.User;
import com.yangxin.core.service.UserService;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    
    @Override
    public void addUser(User user) {
        userDao.insertUser(user);
        System.out.println("添加成功");
    }

    @Override
    public void deleteUser(String name) {
        userDao.deteleUser(name);
        System.out.println("刪除成功");
    }

}

 

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

 

接下來看下切面代碼

package com.yangxin.core.transaction;

import org.aspectj.lang.ProceedingJoinPoint;

import com.yangxin.core.pojo.User;

public class TransactionDemo {
    
    //前置通知
    public void startTransaction(){
        System.out.println("begin transaction ");
    }
    
    //后置通知
    public void commitTransaction(){
        System.out.println("commit transaction ");
    }
    
    //環繞通知
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("begin transaction");
        //調用process()方法才會真正的執行實際被代理的方法
        joinPoint.proceed();
        
        System.out.println("commit transaction");
    }
    
}

 

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

<aop:config>
  <aop:pointcut expression="execution(* com.yangxin.core.service.*.*.*(..))" id="p1" /> <!--切點-->
  <aop:aspect ref = "transactionDemo"> <!--切面 -->
    <aop:before method="startTransaction" pointcut-ref="p1" /> <!--前置通知-->
    <aop:after-returning method="commitTransaction" pointcut-ref="p1"/> <!--后置通知-->
  </aop:aspect>
</aop:config>

 

這里沒有演示環繞通知

好了,運行測試代碼

測試代碼如下

@Test
    public void test1(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
        
        UserService userService = applicationContext.getBean(UserService.class);
        
        User user = new User();
        
        user.setAge(19);
        user.setName("yangxin");
                
        userService.addUser(user);
        userService.deteleUser("yangxin");
        
    }

 

控制台輸出如下

  begin transaction

  添加成功

  commit transaction

  begin transaction

  刪除成功

  commit transaction

現在來測試一下環繞通知

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

修改后的代碼

<aop:config>
  <aop:pointcut expression="execution(* com.yangxin.core.service.*.*.*(..))" id="p1" />
  <aop:aspect ref = "transactionDemo">
    <aop:around method="around" pointcut-ref="p1"/>
  </aop:aspect>
</aop:config>

 

運行測試代碼

輸出如下

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

 

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

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

package com.yangxin.core.transaction;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TransactionDemo2 {
    
    @Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
    public void point(){
        
    }
    
    @Before(value="point()")
    public void before(){
        System.out.println("transaction begin");
    }
    
    @AfterReturning(value = "point()")
    public void after(){
        System.out.println("transaction commit");
    }
    
    @Around("point()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("transaction begin");
        joinPoint.proceed();
        System.out.println("transaction commit");
        
    }
}

 

在applicationContext.xml中配置

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

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

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

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

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

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

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


免責聲明!

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



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