1 Service
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
@Override
public void saveAccount() {
System.out.println("執行了保存");
}
@Override
public void updateAccount(int i) {
System.out.println("執行了更新 " + i);
}
@Override
public int deleteAccount() {
System.out.println("執行了刪除");
return 0;
}
}
2 bean.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"
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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
<!--配置spring創建容器時需要掃描的包-->
<context:component-scan base-package="com.tzb"></context:component-scan>
<!--配置 spring 開啓註解 AOP的支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3 切面類
/**
* 用於記錄日誌的工具類
*/
@Component("logger")
@Aspect // 表示當前類是一個切面類
public class Logger {
@Pointcut("execution(* com.tzb.service.impl.*.*(..))")
private void pt1(){
}
// 前置通知
@Before("pt1()")
public void beforePrintLog() {
System.out.println("前置通知 Logger類中的 beforePrintLog 開始記錄日誌。。。");
}
// 後置通知
@AfterReturning("pt1()")
public void afterReturningPrintLog() {
System.out.println("後置通知 Logger類中的 afterReturningPrintLog 開始記錄日誌。。。");
}
// 異常通知
@AfterThrowing("pt1()")
public void afterThrowingPrintLog() {
System.out.println("異常通知 Logger類中的 afterThrowingPrintLog 開始記錄日誌。。。");
}
// 最終通知
@After("pt1()")
public void afterPrintLog() {
System.out.println("最終通知 Logger類中的 afterPrintLog 開始記錄日誌。。。");
}
/**
* 環繞通知
* 問題:切入點方法沒有執行,而通知方法執行了
* <p>
* 分析:
* 通過對比動態代理中的環繞通知,發現動態代理的環繞通知有明確的切入點方法調用,我們的方法沒有
* <p>
* 解決:
* Spring 提供ProceedingJointPoint ,該接口有一個 proceed(),此方法就相當於明確調用切入點方法
* 該接口可以作爲環繞通知的方法參數,在程序執行時,spring會爲我們提供該接口的實現類供我們使用
*/
//@Around("pt1()")
public Object aroundPrintLog(ProceedingJoinPoint pjp) {
Object rtValue = null;
// 明確調用業務層方法(切入點方法)
try {
Object[] args = pjp.getArgs();
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。前置");
rtValue = pjp.proceed(args);
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。後置");
return rtValue;
} catch (Throwable t) {
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。異常通知");
throw new RuntimeException(t);
} finally {
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。最終通知");
}
}
}
- 單元測試
public class AOPTest {
public static void main(String[] args) {
// 1.獲取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:bean.xml");
// 2. 獲取對象
IAccountService as = (IAccountService) ac.getBean("accountService");
// 3.執行方法
as.saveAccount();
}
}
- 發現 後置通知 在 最終通知的前面
- 加入異常
- 最終通知 在 異常通知的前面
3.1 切面類使用環繞通知
- 建議如果使用註解的話,使用環繞通知
- 切面類
/**
* 用於記錄日誌的工具類
*/
@Component("logger")
@Aspect // 表示當前類是一個切面類
public class Logger {
@Pointcut("execution(* com.tzb.service.impl.*.*(..))")
private void pt1(){
}
// 前置通知
// @Before("pt1()")
public void beforePrintLog() {
System.out.println("前置通知 Logger類中的 beforePrintLog 開始記錄日誌。。。");
}
// 後置通知
// @AfterReturning("pt1()")
public void afterReturningPrintLog() {
System.out.println("後置通知 Logger類中的 afterReturningPrintLog 開始記錄日誌。。。");
}
// 異常通知
// @AfterThrowing("pt1()")
public void afterThrowingPrintLog() {
System.out.println("異常通知 Logger類中的 afterThrowingPrintLog 開始記錄日誌。。。");
}
// 最終通知
//@After("pt1()")
public void afterPrintLog() {
System.out.println("最終通知 Logger類中的 afterPrintLog 開始記錄日誌。。。");
}
/**
* 環繞通知
* 問題:切入點方法沒有執行,而通知方法執行了
* <p>
* 分析:
* 通過對比動態代理中的環繞通知,發現動態代理的環繞通知有明確的切入點方法調用,我們的方法沒有
* <p>
* 解決:
* Spring 提供ProceedingJointPoint ,該接口有一個 proceed(),此方法就相當於明確調用切入點方法
* 該接口可以作爲環繞通知的方法參數,在程序執行時,spring會爲我們提供該接口的實現類供我們使用
*/
@Around("pt1()")
public Object aroundPrintLog(ProceedingJoinPoint pjp) {
Object rtValue = null;
// 明確調用業務層方法(切入點方法)
try {
Object[] args = pjp.getArgs();
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。前置");
rtValue = pjp.proceed(args);
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。後置");
return rtValue;
} catch (Throwable t) {
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。異常通知");
throw new RuntimeException(t);
} finally {
System.out.println("環繞通知 Logger類中的 aroundPrintLog 開始記錄日誌。。。最終通知");
}
}
}