pom.xml
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--解析切入點表達式--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> </dependencies>
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" 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"> <!--配置spring的IOC,把service對象配置進來--> <bean id="accountService" class="com.service.impl.AccountServiceImpl"> </bean> <!--spring中基於XML的AOP配置步驟 1.把通知Bean也餓交給spring來管理 2.使用aop:config標簽表明開始AOP的配置 3.使用aop:aspect標簽表明開始配置切面 id屬性:是給切面提供一個唯一標識 ref屬性:是指定通知類的bean的Id 4.在aop:aspect標簽的內部使用對應標簽來配置通知的類型 我們現在實例是讓pringLog方法在切入點方法執行之前執行,所以是前置通知 aop:before:表示配置前置通知 method屬性:用於指定Logger類中哪個方法是前置通知 pointcut屬性:用於指定切入點表達式,該表達式的含義指的是對業務層中哪些方法增強 切入點表達式的寫法: 關鍵字:execution(表達式) 表達式: 訪問修飾符 返回值 包名.包名.包名...類名.方法名(參數列表) 標准的表達式寫法: public void com.itheima.service.impl.AccountServiceImpl.saveAccount() 包名可以使用通配符,表示任意包,但是有幾級包,就需要寫幾個*. 包名可以使用..表示當前包及其子包 * *..AccountServiceImpl.saveAccount() 類名和方法名都可以使用*號來實現統配 * *..*.*() 參數列表: 可以直接寫數據類型: 基本類型直接寫名稱 int 引用類型寫包名.類名的方式 java.lang.String 可以使用通配符表示任意類型,但是必須有參數 可以使用..表示有無參數均可,有參數可以是任意類型 全通配寫法: * *..*.*(..) 實際開發中切入點表達的通常寫法: 且到業務層實現類下的所有方法 * com.service.impg.*.*(..) --> <!--配置Logger類--> <bean id="logger" class="com.utils.Logger"></bean> <!--配置AOP--> <aop:config> <aop:aspect id="logAdvic" ref="logger"> <aop:pointcut id="pt" expression="execution(* com.service.impl.*.*(..))"/> <!--環繞通知--> <aop:around method="aroundPrintLog" pointcut-ref="pt"></aop:around> </aop:aspect> </aop:config> </beans>
代碼
import org.aspectj.lang.ProceedingJoinPoint; /** * 用於記錄日志的工具類,它里面提供了公共的代碼 */ public class Logger { /** * 用於打印日志:計划讓其在切入點方法執行之前執行(切入點方法就是業務層方法) * 環繞通知 * 當我們配置了環繞通知之后,切入點方法沒有執行,而通知方法執行了。 * 分析:通過對比動態代理中的環繞通知代碼,發現動態代理的環繞通知有明企鵝的切入點方法調用,而我們的代碼中沒有 * 解決: * spring框架為我們提供了一個接口:ProcedingJoinPoint。該接口有一個方法proced(),此方法就相當於明確調用切入點方法。 * 該接口可以作為環繞通知的方法參數,在程序運行時,spring框架會為我們提供該接口的實現類供我們使用。 * * spring中的環繞通知: * 它是spring框架為我們提供的一種可以在代理中手動控制增強方法何時執行的方式。 */ /* public void aroundPrintLog(){*/ public Object aroundPrintLog(ProceedingJoinPoint pjp){ Object rtValue=null; try { System.out.println("環繞通知 Logger類中的aroundPrintLog方法開始記錄日志了。。。前置"); Object [] args=pjp.getArgs(); //得到方法執行所需的參數 rtValue= pjp.proceed(); //明確調用業務層方法(切入點方法) System.out.println("環繞通知 Logger類中的aroundPrintLog方法開始記錄日志了。。。后置"); return rtValue; } catch (Throwable throwable) { //throwable.printStackTrace(); System.out.println("環繞通知 Logger類中的aroundPrintLog方法開始記錄日志了。。。異常"); throw new RuntimeException(throwable); } finally { System.out.println("環繞通知 Logger類中的aroundPrintLog方法開始記錄日志了。。。最終"); } /* System.out.println("環繞通知 Logger類中的aroundPrintLog方法開始記錄日志了。。。");*/ } }