AOP 為 Aspect Oriented Programming 的縮寫,意思為面向切面編程。
AOP相關術語:
目標對象(Target):
你要去代理的對象,可以理解為之前很單純的那個對象。
代理對象(Proxy):
你把你那個單純的對象給我,我給你一個更強的對象。
連接點(Joinpoint):
所謂的連接點就是指哪些可以被攔截到的方法。
切入點(Pointcut):
對連接點再去具體一點,真正要攔截的方法。
通知/增強(Advice):
你把方法攔截了,你要干嘛?要去做一些增強(通知),前置通知、后置通知、異常通知、最終通知、環繞通知。
切面(Aspect):
切入點和通知的結合。
總結以上術語的圖:

AOP開發明確事項:
1. 編寫核心業務代碼(目標類的目標方法)切入點。
2. 把公用代碼抽取出來,制作成通知(增強功能方法)通知。
3. 在配置文件中,聲明切入點與通知間的關系,即切面。
導入AOP相關坐標:
<!-- aspectj的織入(切點表達式需要用到該jar包) -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.13</version>
</dependency>
創建目標接口和目標實現類:
public interface AccountService {/* 目標方法: 切入點 要進行攔截的方法 */public void transfer();
}
public class AccountServiceImpl implements AccountService {/*要切入的方法*/@Overridepublic void transfer() {System.out.println("this is transfer method");}
}
創建通知類:
?這個類里面寫的就是具體怎么去增強對象。
public class MyAdvice {/*** 前置通知*/public void before() {System.out.println("before advice");}/*** 后置通知*/public void after() {System.out.println("after advice");}}
將目標類和通知類對象創建權交給spring:
<!--目標類交給IOC容器--><bean id="accountService" class="com.findyou.service.Impl.AccountServiceImpl"></bean><!--通知類交給IOC容器--><bean id="myAdvice" class="com.findyou.advice.Myadvice"></bean>
?xml里面的aop配置:
xml里面的aop配置,用的是<aop:config>。
里面寫你寫好的通知類,也就是你要用哪個類去增強我的對象,用ref去引入,前提是你已經把這個類放到ioc容器里面了。用的標簽是<aop:aspect ret = "">。
?在這個基礎上再進行續寫,這個通知類里面有很多的方法啊,你要說出來,哪一個是前置通知,哪一個是后置通知等等。前置通知也即是執行原方法之前要做的事情。前置通知的標簽是<aop:before>, 里面的參數有 method = "類里面的哪個方法", pointcut = "你要限制誰,增強誰",可以理解為:當我觸發pointcut里面的方法的時候之前就回去執行 method里面的方法。
?無論是 前置通知和后置通知,里面都要有個屬性:pointcut, point里面寫的就是下面要講的 切點表達式。如果這個要經常去寫的話,可以把pointcut給提取出來。用的時候把之前的pointcut屬性改為?pointcut-ref? =? "提取出來的pointcutId";
<aop:pointcut id="myPointcut" expression="execution(* com.findyou.service.Impl.AccountServiceImpl.*(..))" />
切點表達式:
execution([修飾符] 返回值類型 包名.類名.方法名(參數))
- ?訪問修飾符可以省略
- 返回值類型、包名、類名、方法名可以使用星號 * 代替,代表任意
- 包名與類名之間一個點 . 代表當前包下的類,兩個點 .. 表示當前包及其子包下的類
- 參數列表可以使用兩個點 .. 表示任意個數,任意類型的參數列表。
當然最常用的也還是:?* com.findyou.service.Impl.AccountServiceImpl.*? 這樣的格式。?
總的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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--目標類交給IOC容器--><bean id="accountService" class="com.findyou.service.Impl.AccountServiceImpl"></bean><!--通知類交給IOC容器--><bean id="myAdvice" class="com.findyou.advice.Myadvice"></bean><!-- AOP配置 --><aop:config><!--execution 翻譯為 執行--><!-- 定義切點與通知 --><aop:aspect ref="myAdvice"><!-- 切點表達式,指定在哪些方法執行前后添加通知 --><aop:pointcut id="myPointcut" expression="execution(* com.findyou.service.Impl.AccountServiceImpl.*(..))" /><!-- 將通知應用于切點 配置的是前置通知 --><aop:before method="before" pointcut = "execution(public void com.findyou.service.Impl.AccountServiceImpl.transfer())"/><aop:after-returning method="after" pointcut-ref="myPointcut"/></aop:aspect></aop:config></beans>
測試代碼:
package com.findyou;import com.findyou.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** @Title: MyTest* @Author FindYou* @Package com.findyou* @Date 2024/12/5 上午11:17* @description: 測試類*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {@Autowiredprivate AccountService accountService;@Testpublic void testTransfer() throws Exception {accountService.transfer(); // 先去執行的是前置通知}}