目錄
1. Web MVC發(fā)展史歷程
2.Spring概要
3.Spring-依賴注入概要(IOC)
4.屬性注入的三種實現(xiàn)方式
5.Spring-IoC XML裝配
6.Spring-XML設置Bean的值
7.Spring-IoC 注解(1)
8.Spring-IoC 注解(2)
9.Spring-AOP切面編程(1)
10.Spring-AOP切面編程(2)
11.Spring-AOP切面編程(3)
六淹父、基于@Aspect注解編程(重點)
1柜与、說明
Spring 使用了和AspectJ 一樣的注解并使用AspectJ來做切入點解析和匹配。但是,AOP在運行時仍舊是純的Spring AOP,并不依賴于AspectJ的編譯器或者織入器(weaver)(編譯器與織入器暫時不要管)
2、啟用@AspectJ支持
- 說明
為了在Spring中使用@AspectJ切面羊初,你首先必須啟用Spring對@AspectJ切面配置的支持,并確保開啟自動代理什湘。自動代理是指Spring會判斷一個bean是否使用了一個或多個切面通知长赞,并據(jù)此自動生成相應的代理以攔截其方法調(diào)用,并且確保通知在需要時執(zhí)行 - 新建spring-aspect.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" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.wener.example.aop.aspect"/> <!-- 有了這個Spring就能夠自動掃描被@Aspect標注的切面了 --> <!-- 開啟自動代理 --> <aop:aspectj-autoproxy/> </beans>
2闽撤、聲明一個切面
- 說明
在代碼中定義一個類任意在類上使用@Aspect注解 - 示例代碼
import org.aspectj.lang.annotation.Aspect; @Aspect public class LogAspect { }
3得哆、聲明一個切入點
- 說明
切入點決定了連接點關注的內(nèi)容,使得我們可以控制通知什么時候執(zhí)行腹尖。Spring AOP只支持Spring bean的方法執(zhí)行連接點柳恐。所以你可以把切入點看做是Spring bean上方法執(zhí)行的匹配。一個切入點聲明有兩個部分:-
包含名字和任意參數(shù)的簽名:一個切入點簽名通過一個普通的方法定義來提供热幔,并且切入點表達式使用
@Pointcut
注解來表示(作為切入點簽名的方法必須返回void
類型) - 切入點表達式:切入點表達式?jīng)Q定了我們關注哪些方法的執(zhí)行,詳細表達式語法后面在說乐设。
-
包含名字和任意參數(shù)的簽名:一個切入點簽名通過一個普通的方法定義來提供热幔,并且切入點表達式使用
- 語法格式
@Pointcut(value="", argNames = "")
- 參數(shù)說明
- value
指定切入點表達式 - argNames
指定命名切入點方法參數(shù)列表參數(shù)名字,可以有多個用“绎巨,”分隔近尚,這些參數(shù)將傳遞給通知方法同名的參數(shù)
- value
- 示例代碼
@Aspect public class LogAspect { // 也可以在通知上定義,當需要復用切入點的時候 @Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))") // 返回值 必須是void類型 public void log() { } }
- 備注
切入點的定義是非必要的,也可以直接在通知上使用切入點表達式
4、聲明通知
4.1场勤、說明
通知是跟一個切入點表達式關聯(lián)起來的戈锻,并且在切入點匹配的方法執(zhí)行之前或者之后或者前后運行。 切入點表達式可能是指向已命名的切入點的簡單引用或者是一個已經(jīng)聲明過的切入點表達式和媳,通知的類型就是我們前面提到過的類型
4.2格遭、前置通知
- 說明
在關注點執(zhí)行前運行的方法,切面里使用@Before
注解聲明前置通知 - 語法格式
@Before(value = "", argNames = "")
- 參數(shù)說明
- value :指定切入點表達式或切入點名字留瞳;
- argNames: 用來接收AspectJ表達式中的參數(shù),并指定通知方法中的參數(shù)
- 示例代碼
import org.springframework.stereotype.Component; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Before; @Aspect @Component public class LogAspect { /** * @Pointcut() 切入點表達式 */ @Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))") public void logPointcut() { } /** * @Before 前置通知 * value:指定切入點表達式或命名切入點拒迅; * argNames:與Schema方式配置中的同義; */ @Before("logPointcut()") public void before() { System.out.println("前置通知"); } }
4.3她倘、后置通知(最終通知)
- 說明
不論一個方法是如何結束的璧微,最終通知都會運行。使用@After
注解來聲明硬梁。最終通知必須準備處理正常返回和異常返回兩種情況前硫。通常用它來釋放資源。相當于異常處理里finally的代碼 - 語法格式
@After(value = "", argNames = "")
- 參數(shù)
- value :指定切入點表達式或切入點名字荧止;
- **argNames: **用來接收AspectJ表達式中的參數(shù),并指定通知方法中的參數(shù)
- 示例代碼
import org.springframework.stereotype.Component; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Before; @Aspect @Component public class LogAspect { /** * @Pointcut() 切入點表達式 */ @Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))") public void logPointcut() { } /** * @After 后置通知 */ @After(value = "logPointcut()") public void after() { System.out.println("后置通知"); } }
4.4屹电、返回通知
- 說明
返回后通知通常在一個匹配的方法返回的時候執(zhí)行阶剑。使用@AfterReturning
注解來聲明 - 語法格式
@AfterReturning(value="",pointcut="",returning="",argNames="")
- 參數(shù)說明
- value:指定切入點表達式或切入點名字;
- pointcut:指定切入點表達式或命名切入點嗤详,如果指定了將覆蓋value屬性的个扰,pointcut具有高優(yōu)先級瓷炮;
- returning:如果你想獲取方法的返回值可以使用該參數(shù),在通知方法中定義參數(shù)就可以了
- argNames:用來接收AspectJ表達式中的參數(shù),并指定通知方法中的參數(shù)
- 示例代碼
import org.springframework.stereotype.Component; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.ProceedingJoinPoint; @Aspect @Component public class LogAspect { /** * @Pointcut() 切入點表達式 */ @Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))") public void logPointcut() { } /** * 不獲取方法的返回值 */ @AfterReturning(value = "logPointcut()") public void AfterReturning1() { System.out.println("異常通知"); } /** * 獲取方法的返回值 * returning的賦值的名字,必須跟通知方法中參數(shù)的名字保持一致 */ @AfterReturning(value = "logPointcut()", returning = "val") public Object afterReturning(Object val) { System.out.println("返回后通知"); return val; } }
4.5葱色、異常通知
- 說明
拋出異常通知在一個方法拋出異常后執(zhí)行。使用@AfterThrowing
注解來聲明 - 語法格式
@AfterThrowing(value="",pointcut="",throwing="",argNames="")
- 參數(shù)說明
- value:指定切入點表達式或命名切入點娘香;
- pointcut:指定切入點表達式或命名切入點苍狰,如果指定了將覆蓋value屬性的,pointcut具有高優(yōu)先級烘绽;
- throwing:異常類型淋昭;并且在通知方法中定義異常參數(shù);
- argNames:用來接收AspectJ表達式中的參數(shù),并指定通知方法中的參數(shù)安接;
- 示例代碼
import org.springframework.stereotype.Component; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.ProceedingJoinPoint; @Aspect @Component public class LogAspect { /** * @Pointcut() 切入點表達式 */ @Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))") public void logPointcut() { } /** * @AfterThrowing 異常通知 * value:指定切入點表達式或命名切入點翔忽; * throwing:異常類型。 */ @AfterThrowing("logPointcut()") public void afterThrowing() { System.out.println("異常通知"); } /** * 如果想要限制通知只在某種特定的異常被拋出的時候匹配盏檐,同時還想知道異常的一些信息歇式。 * 那我們就需要使用throwing屬性聲明響應 */ @AfterThrowing(value = "logPointcut()", throwing = "exception") public void afterThrowing(Exception exception) { System.out.println("異常通知"); } }
4.6、環(huán)繞通知
- 說明
環(huán)繞通知在一個方法執(zhí)行之前和之后執(zhí)行胡野。它使得通知有機會 在一個方法執(zhí)行之前和執(zhí)行之后運行材失。而且它可以決定這個方法在什么時候執(zhí)行,如何執(zhí)行硫豆,甚至是否執(zhí)行龙巨。 環(huán)繞通知經(jīng)常在某線程安全的環(huán)境下,你需要在一個方法執(zhí)行之前和之后共享某種狀態(tài)的時候使用熊响。 請盡量使用最簡單的滿足你需求的通知旨别。(比如如果簡單的前置通知也可以適用的情況下不要使用環(huán)繞通知)。- 使用
@Around
注解汗茄; - 環(huán)繞通知需要攜帶ProceedingJoinPoint類型的參數(shù)秸弛;
- 且環(huán)繞通知必須有返回值,返回值即為有目標方法的返回值剔难。
- 使用
- 語法格式
@Around(value = "", argNames = "")
- 參數(shù)
- value :指定切入點表達式或切入點名字胆屿;
- **argNames: **用來接收AspectJ表達式中的參數(shù),并指定通知方法中的參數(shù)
- 示例代碼
import org.springframework.stereotype.Component; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.ProceedingJoinPoint; @Aspect @Component public class LogAspect { /** * @Pointcut() 切入點表達式 */ @Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))") public void logPointcut() { } /** * @Around 環(huán)繞通知 * 比如 緩存切面,如果緩存中有值偶宫,就返回該值非迹,否則調(diào)用proceed()方法 * value:指定切入點表達式或命名切入點; * 注意 第一個參數(shù)必須是 ProceedingJoinPoint對象 具體這個類的更多詳細使用看附錄: */ @Around(value = "logPointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("環(huán)繞通知1"); Object obj = pjp.proceed(); System.out.println("環(huán)繞通知2"); return obj; } }
4.7纯趋、通知參數(shù)
- 說明
若想要在通知方法獲取被通知方法的參數(shù)共有兩種方式:自動獲取憎兽、手動指定- 自動獲取參數(shù):通知類型可以通過參數(shù)JoinPoint或者 ProceedingJoinPoint 自動獲取被通知方法的參數(shù)值并調(diào)用該方法
- 手動指定參數(shù):即在配置切面時冷离,需在切面的通知與切面的切點中明確指定參數(shù)。
- 手動指定
- 在@pointcut中切入表達式中使用args聲明匹配的參數(shù),注意使用&&連接args
- 在@pointcut中切入表達式中使用參數(shù)argNames用來接收AspectJ表達式中的參數(shù)纯命,
argNames屬性是用于指定在表達式中應用的參數(shù)名與Advice方法參數(shù)是如何對應的 - 在通知方法中定義參數(shù)
- 手動獲取指定參數(shù)
import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Aspect @Component public class LogAdviceParamsAspect { // 注意參數(shù)的個數(shù)必須一致,否則匹配不到 @Before(value = "execution(* com.wener.example.aop.aspect.*.*(..))&& args(id,name)", argNames = "id,name") public void testArgs(Object id, Object name) { System.out.println(id); System.out.println(name); } }
- 混用使用
當同時采用自動獲取參數(shù)與手動指定參數(shù)時西剥,自動獲取參數(shù)必須是第一個參數(shù),即ProceedingJoinPoint 等參數(shù)并需是通知方法定義的第一個參數(shù)import org.aopalliance.intercept.Joinpoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Aspect @Component public class LogAdviceParamsAspect { // args亿汞、argNames的參數(shù)名與testArgs()方法中參數(shù)名 保持一致 @Before(value = "execution(* com.wener.example.aop.aspect.*.*(..))&& args(id,name)", argNames = "id,name") public void testArgs(Object id, Object name) { System.out.println(id); System.out.println(name); } // 也可以不用argNames @Before(value = "execution(* com.wener.example.aop.aspect.*.*(..))&& args(id,name)") public void testArgs(Object id, Object name) { System.out.println(id); System.out.println(name); } @Around(value = "execution(* com.wener.example.aop.aspect.*.*(..))&&(args(id,name,..))", argNames = "pjp,id,name") public Object testAroundArgs(ProceedingJoinPoint pjp, Object id, Object name) throws Throwable { System.out.println("Around之前"); Object obj = pjp.proceed(); System.out.println(); return obj; } }
4.8 瞭空、引入
- 說明
有時候有一組共享公共行為類。在OOP中疗我,它們必須擴展相同的基類或者實現(xiàn)相同的接口咆畏。此外,Java的單繼承機制僅允許一個類最多擴展一個基類吴裤。所以旧找,不能同時從多個實現(xiàn)類中繼承行為。
解決方案:引入是AOP中的一種特殊的通知麦牺。它允許為一個接口提供實現(xiàn)類钮蛛,使對象動態(tài)的實現(xiàn)接口。就像對象在運行時擴展了實現(xiàn)類剖膳。而且魏颓,可以用多個實現(xiàn)類將多個接口同時引入對象。這可以實現(xiàn)與多重繼承相同的效果潮秘。 - 在開發(fā)中用的不是很多,所以不做過多的分析
5琼开、聲明代理類
- 說明
被代理的對象,跟前面說的一樣,代理接口或者類都可以 - 示例代碼
public interface AspectDao { public void test(); public void testParams(int id, String name); public void testParams(Joinpoint jp, int id, String name); } @Component("aspectDao") public class AspectDaoImpl implements AspectDao { @Override public void test() { System.out.println("核心測試方法"); } @Override public void testParams(int id, String name) { System.out.println("帶參數(shù)的方法:" + "ID:" + id + "name:" + name); } }
6、測試
- 示例代碼
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aspect.xml"); AspectDao dao = (AspectDao) context.getBean("aspectDao"); dao.test(); dao.testParams(1,"hello");
7枕荞、總結
- 使用@Aspect將POJO聲明為切面柜候;
- 在切面類中使用@Pointcut進行命名切入點聲明;
- 定義通知方法,使用5中注解聲明躏精,其中value用于定義切入點表達式或引用命名切入點渣刷;
- 配置文件需要使用
<aop:aspectj-autoproxy/>
來開啟注解風格的@AspectJ支持; - 將切面類和POJO類注冊到Spring容器中
七矗烛、基于xml的AOP編程(掌握)
1辅柴、說明
如果比較喜歡使用XML格式,Spring2.0也提供了使用新的"aop"命名空間來定義一個切面瞭吃。 和使用@AspectJ風格完全一樣碌嘀,切入點表達式和通知類型同樣得到了支持
AOP配置元素 用途 <aop:config>
頂層的AOP配置元素,大多數(shù)的 <aop:*>
必須包含在<aop:config>
元素內(nèi)<aop:aspect>
定義一個切面 <aop:pointcut>
定義一個切點 <aop:advisor>
定義AOP通知器 <aop:before>
定義AOP前置通知 <aop:around>
定義AOP環(huán)繞通知 <aop:after-returning>
定義AOP返回通知 <aop:after-throwing>
定義AOP異常通知 <aop:after>
定義AOP后置通知(不管被通知的方法是否執(zhí)行成功) <aop:aspectj-autoproxy>
啟用@Aspect注解的切面 <aop:declare-parents>
以透明的方式為被通知的對象引入額外的接口
2、引入aop命名空間標簽
- 說明
在beans元素下 引入aop歪架,聲明<aop-config>
股冗,在配置文件中,我們可以聲明多個<aop-config>
和蚪。
注意:- 所有的切面和通知都必須定義在
<aop:config>
元素內(nèi)部。 - 一個
<aop:config>
可以包含pointcut,advisor和aspect元素 (注意這三個元素必須按照這個順序進行聲明)
- 所有的切面和通知都必須定義在
- 示例代碼
<beans ... xmlns:aop="http://www.springframework.org/schema/aop"> ... <aop:config> </aop:config> </beans>
3掸冤、聲明一個切面
- 說明
切面使用<aop:aspect>
來聲明 - 示例代碼
<aop:config> <aop:aspect id="myAspect" ref="myBean"> ... </aop:aspect> </aop:config> <bean id="myBean" class="..."> ... </bean>
4、聲明一個切入點
- 說明
一個命名切入點可以在<aop:config>
元素中定義浆洗,使用<aop:pointcut>
聲明,這樣多個切面和通知就可以共享該切入點集峦,你也可以在切面中定義 - 示例代碼
<aop:config> <aop:pointcut id="servicePointcut" expression="execution(* *.*(..))"/> </aop:config>
<aop:config> <aop:aspect id="myAspect" ref="myBean"> <!--這個切入點只能在該 切面中使用 --> <aop:pointcut id="servicePointcut" expression="execution(* *.*(..))"/> </aop:aspect> </aop:config>
5伏社、聲明通知
5.1、說明
和@AspectJ風格一樣少梁,基于xml的風格也支持5種通知類型并且兩者具有同樣的語義
5.2洛口、前置通知
- 說明
前置通知在匹配方法執(zhí)行前運行。在<aop:aspect>
中使用<aop:before>
元素來聲明它 - 示例代碼
<aop:config> <aop:pointcut id="servicePointcut" expression="execution(* *.*(..))"/> <aop:aspect id="beforeExample" ref="myBean"> <aop:before pointcut-ref="servicePointcut" method="doBefore"/> </aop:aspect> </aop:config>
5.3凯沪、后置通知
- 說明
后置通知在匹配的方法完全執(zhí)行后運行。和前置通知一樣买优,在<aop:aspect>
里面使用<aop:after-returning>
聲明妨马,通知方法可以得到返回值。使用returning屬性來指定傳遞返回值的參數(shù)名杀赢。 - 示例代碼
<aop:aspect id="afterReturningExample" ref="myBean"> <aop:after-returning pointcut-ref="servicePointcut" method="doAfterReturning"/> ... </aop:aspect>
<aop:aspect id="afterReturningExample" ref="myBean"> <aop:after-returning pointcut-ref="servicePointcut" method="doAfterReturning"/> ... </aop:aspect>
?
5.4烘跺、異常通知
- 說明
異常通知在匹配方法拋出異常退出時執(zhí)行。在<aop:aspect>
中使用<after-throwing>
元素來聲明脂崔,還可以使用throwing屬性來指定傳遞異常的參數(shù)名 - 示例代碼
<!-- 無返回值 --> <aop:aspect id="afterThrowingExample" ref="myBean"> <aop:after-throwing pointcut-ref="servicePointcut" throwing="exception" method="doAfterThrowing"/> ... </aop:aspect>
5.5滤淳、最終通知
- 說明
最終通知無論如何都會在匹配方法退出后執(zhí)行。在<aop:aspect>
中使用<aop:after>
元素來聲明 - 示例代碼
<aop:aspect id="afterFinallyExample" ref="myBean"> <aop:after pointcut-ref="servicePointcut" method="doAfter"/> ... </aop:aspect>
5.6砌左、環(huán)繞通知
- 說明
環(huán)繞通知在匹配方法運行期的“周圍”執(zhí)行脖咐。 它有機會在目標方法的前面和后面執(zhí)行,并決定什么時候運行汇歹,怎么運行屁擅,甚至是否運行。環(huán)繞通知經(jīng)常在需要在一個方法執(zhí)行前后共享狀態(tài)信息产弹,并且是在線程安全的情況下使用 - 示例代碼
<aop:aspect id="aroundExample" ref="myBean"> <aop:around pointcut-ref="servicePointcut" method="doAround"/> ... </aop:aspect>
八派歌、切面的優(yōu)先級
1、說明
在同一個連接點上應用不止一個切面時, 除非明確指定, 否則它們的優(yōu)先級是不確定的
切面的優(yōu)先級可以通過實現(xiàn) Ordered 接口或利用 @Order 注解指定.
實現(xiàn) Ordered 接口, getOrder() 方法的返回值越小, 優(yōu)先級越高.若使用 @Order 注解, 序號出現(xiàn)在注解中痰哨,值越小優(yōu)先級越高
2胶果、示例代碼
- 基于實現(xiàn)接口(了解)
@Aspect @Component public class LoggingAspect implements Ordered { @Override public int getOrder() { return 2; } }
@Aspect @Component public class ValidateAspect implements Ordered { @Override public int getOrder() { return 1; } }
- 基于注解
@Order(2) @Aspect @Component public class LoggingAspect { }
@Order(1) @Aspect @Component public class ValidateAspect { }
九、簡單總結
- 切面的內(nèi)容可以復用
- 避免使用Proxy斤斧、CGLIB生成代理早抠,這方面的工作全部框架去實現(xiàn),開發(fā)者可以專注于切面內(nèi)容本身
- 代碼與代碼之間沒有耦合折欠,如果攔截的方法有變化修改配置文件即可
十贝或、附錄
1吼过、獲取目標對象信息
1.1、JoinPoint 對象
- 說明
JoinPoint對象封裝了SpringAop中切面方法的信息,在切面方法中添加JoinPoint參數(shù),就可以獲取到封裝了該方法信息的JoinPoint對象 - 重要方法
方法 說明 Signature getSignature(); 獲取封裝了署名信息的對象,在該對象中可以獲取到目標方法名,所屬類的Class等信息 Object[] getArgs(); 獲取連接點方法運行時的入?yún)⒘斜?/strong> Object getTarget(); 獲取連接點所在的目標對象 Object getThis(); 獲取代理對象本身
1.2咪奖、ProceedingJoinPoint
- 說明
ProceedingJoinPoint繼承JoinPoint子接口盗忱,并且只能用于@Around的切面方法中 - 新增方法
方法名 功能 Object proceed() throws Throwable 執(zhí)行目標方法 Object proceed(Object[] var1) throws Throwable 傳入的新的參數(shù)去執(zhí)行目標方法
1.2、示例代碼
- 案例1
Aspect @Component public class JoinPointerAspect { /** * 定義一個切入點表達式,用來確定哪些類需要代理 */ @Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))") public void declareJoinPointer() {} /** * 前置方法,在目標方法執(zhí)行前執(zhí)行 * @param joinPoint 封裝了代理方法信息的對象,若用不到則可以忽略不寫 */ @Before("declareJoinPointer()") public void beforeMethod(JoinPoint joinPoint){ System.out.println("目標方法名:" + joinPoint.getSignature().getName()); System.out.println("目標方法所屬類的名:" + joinPoint.getSignature().getDeclaringType().getSimpleName()); System.out.println("目標方法聲明類型:" + Modifier.toString(joinPoint.getSignature().getModifiers())); //獲取傳入目標方法的參數(shù) Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { System.out.println("第" + (i+1) + "個參數(shù)為:" + args[i]); } System.out.println("被代理的對象:" + joinPoint.getTarget()); System.out.println("代理對象自己:" + joinPoint.getThis()); } /** * 環(huán)繞方法,可自定義目標方法執(zhí)行的時機 * @param pjd JoinPoint的子接口,添加了 * Object proceed() throws Throwable 執(zhí)行目標方法 * Object proceed(Object[] var1) throws Throwable 傳入的新的參數(shù)去執(zhí)行目標方法 * * @return 此方法需要返回值,返回值視為目標方法的返回值 */ @Around("declareJoinPointer()") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; try { //前置通知 System.out.println("目標方法執(zhí)行前..."); //執(zhí)行目標方法 //result = pjd.proeed(); //用新的參數(shù)值執(zhí)行目標方法 result = pjd.proceed(new Object[]{"hello","world"}); //返回通知 System.out.println("目標方法返回結果后..."); } catch (Throwable e) { //異常通知 System.out.println("執(zhí)行目標方法異常后..."); throw new RuntimeException(e); } //后置通知 System.out.println("目標方法執(zhí)行后..."); return result; } }