一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 談談Spring AOP中@Aspect的高級用法示例

談談Spring AOP中@Aspect的高級用法示例

2021-05-26 13:35deniro Java教程

在Spring AOP中目前只有執行方法這一個連接點,下面這篇文章主要給大家介紹了關于Spring AOP中@Aspect的高級用法的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧

前言

本文主要跟大家分享介紹了關于spring aop中@aspect的高級用法,下面話不多說了,來隨著小編一起看看詳細的介紹吧。

1 切點復合運算

支持在切點定義中加入以下運算符進行復合運算:

 

運算符 說明
&& 與運算。
! 非運算。
|| 或運算。

 

2 切點命名

一般情況下,切點是直接聲明在需要增強方法處,這種切點的聲明方式稱為匿名切點,匿名切點只能在聲明處被使用 。 如果希望在其它地方可以重用這個切點,我們可以通過 @pointcut 注解及切面類方法來命名它。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class namepointcut {
 
 /**
 * 切點被命名為 method1,且該切點只能在本類中使用
 */
 @pointcut("within(net.deniro.spring4.aspectj.*)")
 private void method1() {
 }
 
 /**
 * 切點被命名為 method2,且該切點可以在本類或子孫類中使用
 */
 @pointcut("within(net.deniro.spring4.aspectj.*)")
 protected void method2() {
 }
 
 /**
 * 切點被命名為 method3,且該切點可以在任何類中使用
 * 這里還使用了復合運算
 */
 @pointcut("method1() && method2()")
 public void method3() {
 }
}

命名切點的結構如下:

談談Spring AOP中@Aspect的高級用法示例

切點可訪問性修飾符與類可訪問性修飾符的功能是相同的,它可以決定定義的切點可以在哪些類中可使用。

因為命名切點僅利用方法名及訪問修飾符的信息,所以我們一般定義方法的返回類型為 void ,并且方法體為空 。

定義好切點后,就可以在切面類中引用啦:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@aspect
public class namepointcutaspect {
 
 @after("namepointcut.method2()")
 public void aspectmethod1() {
 }
 
 /**
 * 這里使用了復合運算
 */
 @after("namepointcut.method2() && namepointcut.method3()")
 public void aspectmethod2() {
 }
}

3 織入順序

一個連接點可以同時匹配多個切點,而切點所對應的增強在連接點上織入順序的規則是這樣的:

1.如果在同一個切面類中聲明的增強,則按照增強在切面類中定義的順序進行織入;

2.如果增強位于不同的切面類中,并且這些切面類都實現了org.springframework.core.ordered 接口,則由 ordered 方法的順序號決定(順序號小的先織入);

3.如果增強位于不同的切面類中,但這些切面類沒有實現org.springframework.core.ordered 接口,織入的順序是不確定的 。

假設有兩個切面類 a 與 b,它們都實現了 ordered 接口,a 的順序號為 1,b 的順序號為 2,切面類 a 與 b 都定義了 3 個增強,那么同時匹配這 6 個增強的織入順序如下圖所示:

談談Spring AOP中@Aspect的高級用法示例

4 獲取連接點信息

4.1 joinpoint

org.aspectj.lang.joinpoint 接口表示目標類連接點對象,它定義這些主要方法。

 

方法 說明
object[] getargs() 獲取連接點方法運行時的入參列表。
signature getsignature() 獲取連接點的方法簽名對象。
object gettarget() 獲取連接點所在的目標對象。
object getthis() 獲取代理對象。

 

4.2 proceedingjoinpoint

org.aspectj.lang.proceedingjoinpoint 繼承了 joinpoint 接口,它新增了兩個方法(它們用于執行連接點方法)。

方法 說明
object proceed() throws throwable 通過反射執行目標對象連接點處的方法。
object proceed(object[] var1) throws throwable 使用新的入參(替換掉原來的入參),通過反射執行目標對象連接點處的方法。

4.3 示例

cook 接口:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface cook {
 
 /**
 * 制作食品
 */
 void make();
 
 /**
 * 制作
 *
 * @param name 食品名稱
 */
 void make(string name);
}

cooka 類:

?
1
2
3
4
5
6
7
8
9
public class cooka implements cook {
 public void make() {
 system.out.println("制作食品");
 }
 
 public void make(string name) {
 system.out.println("制作" + name);
 }
}

在切面類中訪問連接點信息:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@aspect
public class joinpointaspect {
 
 @around("within(net.deniro.spring4.aspectj.cooka)")
 public void test(proceedingjoinpoint pjp) throws throwable {
 system.out.println("---------獲取連接點對象【開始】---------");
 system.out.println("參數:" + pjp.getargs()[0]);
 system.out.println("簽名對象:" + pjp.gettarget().getclass());
 
 //執行目標對象方法
 pjp.proceed();
 system.out.println("---------獲取連接點對象【結束】---------");
 
 }
}

spring bean 配置:

?
1
2
3
4
5
6
7
8
9
10
11
12
<?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-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 
 <!--aspectj 驅動器 -->
 <aop:aspectj-autoproxy/>
 
 <bean id="cooka" class="net.deniro.spring4.aspectj.cooka"/>
 <bean class="net.deniro.spring4.aspectj.joinpointaspect"/>
</beans>

輸出結果:

---------獲取連接點對象【開始】---------
參數:壽司
簽名對象:class net.deniro.spring4.aspectj.cooka
制作壽司
---------獲取連接點對象【結束】---------

5 綁定連接點的方法入參

args()、this()、target()、@args()、@within()、@target() 和 @annotation() 這些切點函數除可以指定類名外,還可以指定參數名,將目標對象連接點上的方法入參綁定到增強的方法中 。 其中 args() 用于綁定連接點方法的入參, @annotation() 用于綁定連接點方法的注解對象,而 @args() 用于綁定連接點方法入參的注解。

cookc 類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class cookc implements cook {
 public void make() {
 system.out.println("制作食品");
 }
 
 public void make(string name) {
 system.out.println("制作" + name);
 }
 
 public void make(string name, int num) {
 system.out.println("制作" + name + " " + num + " 個");
 }
}

切面類:

?
1
2
3
4
5
6
7
8
9
10
11
12
@aspect
public class paramsaspect {
 
 @before("target(net.deniro.spring4.aspectj.cookc) && args(name,num,..)")
 public void test(string name,int num) {
 system.out.println("----------綁定連接點入參【開始】----------");
 system.out.println("name:" + name);
 system.out.println("num:" + num);
 system.out.println("----------綁定連接點入參【結束】----------");
 
 }
}
  • 這里的連接點表達式 args(name,num,..) 會先找到 name 與 num 的類型,從而生成真正的表達式 args(string,int,..)。
  • 增強方法可以通過 name 與 num 得到連接點的方法入參。

切點匹配和參數綁定的過程是這樣的:

  1. args()會根據參數名稱在增強方法中查到名稱相同的入參并獲得對應參數的類型,這樣就得到了匹配連接點方法的入參類型 。
  2. 連接點方法入參類型所在的位置由參數名在 args() 函數中聲明的位置決定 。

上述示例中的匹配過程如下:

談談Spring AOP中@Aspect的高級用法示例

spring 配置:

?
1
2
3
4
5
<!--aspectj 驅動器 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
 
<bean id="cookc" class="net.deniro.spring4.aspectj.cookc"/>
<bean class="net.deniro.spring4.aspectj.paramsaspect"/>

注意: 這里必須通過 <aop:aspectj-autoproxy proxy-target-class="true" />來啟用 cglib 動態代理,這是因為 cookc 的 public void make(string name, int num) 是該類獨有的方法(非接口定義的方法),所以必須使用 cglib 生成子類的代理方法 。

單元測試:

?
1
2
3
applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml");
cookc cookc = (cookc) context.getbean("cookc");
cookc.make("壽司", 100);

輸出結果:

----------綁定連接點入參【開始】----------
name:壽司
num:100
----------綁定連接點入參【結束】----------
制作壽司 100 個

6 綁定代理對象

使用 this() 或 target() 可綁定被代理對象的實例。通過類實例名綁定對象時,依然具有原來連接點匹配的功能,只是類名是由增強方法中的同名入參類型間接決定的。

?
1
2
3
4
5
6
7
8
9
10
@aspect
public class proxyaspect {
 
 @before("this(cook)")
 public void bind(cook cook) {
  system.out.println("--------綁定代理對象【開始】--------");
  system.out.println(cook.getclass().getname());
  system.out.println("--------綁定代理對象【結束】--------");
 }
}

首先通過 public void bind(cook cook) 找出 cook 所對應的類型,接著轉換切點表達式為 this(net.deniro.spring4.aspectj.cook) 。這樣就表示該切點匹配所有代理對象為 cook 類中的所有方法。

輸出結果:

--------綁定代理對象【開始】--------
net.deniro.spring4.aspectj.cookc$$enhancerbyspringcglib$$217fb793
--------綁定代理對象【結束】--------

target() 綁定與 this() 相似。

7 綁定類注解對象

@within() 和 @target() 函數都可以將目標類的注解對象綁定到增強方法中。

定義一個日志注解類:

?
1
2
3
4
5
@retention(retentionpolicy.runtime)//保留期限
@target({elementtype.method,elementtype.type})//目標類型
public @interface log {
 boolean value() default true;//聲明成員變量
}

把該注解類應用于 cookd:

?
1
2
3
4
5
6
7
8
9
10
@log
public class cookd implements cook {
 public void make() {
  system.out.println("制作糕點");
 }
 
 public void make(string name) {
 
 }
}

綁定類注解對象:

?
1
2
3
4
5
6
7
8
9
10
@aspect
public class classannotationobjectaspect {
 
 @before("@within(log)")
 public void bind(log log){
  system.out.println("----------綁定類注解對象【開始】----------");
  system.out.println(log.getclass().getname());
  system.out.println("----------綁定類注解對象【結束】----------");
 }
}

spring 配置:

?
1
2
3
4
5
6
<!--aspectj 驅動器 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
 
 
<bean id="cookd" class="net.deniro.spring4.aspectj.cookd"/>
<bean class="net.deniro.spring4.aspectj.classannotationobjectaspect"/>

單元測試:

?
1
2
3
applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml");
cookd cook = (cookd) context.getbean("cookd");
cook.make();

輸出結果:

----------綁定類注解對象【開始】----------
com.sun.proxy.$proxy8
----------綁定類注解對象【結束】----------

從輸出結果  com.sun.proxy.$proxy8 可以看出 ,cookd 類的注解 log 對象也被代理咯o(∩_∩)o哈哈~

8 綁定返回值

在后置增強中,可以通過 returning 來綁定連接點方法的返回值。

切面:

?
1
2
3
4
5
6
7
8
9
10
@aspect
public class returnvalueaspect {
 
 @afterreturning(value = "target(net.deniro.spring4.aspectj.cooka)", returning = "value")
 public void bind(boolean value) {
  system.out.println("綁定返回值【開始】");
  system.out.println("value:" + value);
  system.out.println("綁定返回值【結束】");
 }
}

注意:returning 的值必須與方法參數名相同。

cooka 新增 smell 方法:

?
1
2
3
4
public boolean smell(string name) {
 system.out.println(name + "香嗎?");
 return true;
}

單元測試:

?
1
2
3
applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml");
cooka cook = (cooka) context.getbean("cooka");
cook.smell("烤鴨");

輸出結果:

烤鴨香嗎?
綁定返回值【開始】
value:true
綁定返回值【結束】

9 綁定異常

可以使用 afterthrowing 注解的 throwing 成員變量來綁定連接點拋出的異常。

切面類:

?
1
2
3
4
5
6
7
8
9
10
@aspect
public class exceptionaspect {
 
 @afterthrowing(value = "target(net.deniro.spring4.aspectj.cooka)",throwing = "e")
 public void bind(cookexception e){
  system.out.println("綁定異常【開始】");
  system.out.println("e:" + e.getmessage());
  system.out.println("綁定異常【結束】");
 }
}

注意:throwing 的值必須與方法參數名相同。

單元測試:

?
1
2
3
applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml");
cooka cook = (cooka) context.getbean("cooka");
cook.make("");

輸出結果:

綁定異常【開始】
e:煮啥呢???
綁定異常【結束】

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://www.jianshu.com/p/0d7cf0aeb338

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品国语对白精品自拍视 | 美国一级大黄大色毛片 | 91理论片午午伦夜理片久久 | 涩涩屋视频在线观看 | 国产欧美日韩综合二区三区 | 国产高清久久 | 国人精品视频在线观看 | 色先锋av资源中文字幕 | 亚洲AV无码A片在线观看蜜桃 | 精品成人网 | 日本人泡妞xxxxxx69 | 男人与禽交的方法 | 欧美特级特黄a大片免费 | ck7788免费视频 | 免费深夜福利 | 成人性生交小说免费看 | 日韩精品亚洲一级在线观看 | 四虎网站在线 | 四虎影视4hutv最新地址在线 | chinese特色video | 99精品免费在线 | 日本高清视频一区二区 | 日韩无遮挡大尺度啪啪影片 | 大吊小说 | 1024国产高清精品推荐 | 亚洲国产成人综合 | 白丝超短裙被输出娇喘不停小说 | 边摸边吃奶边做爽gif动态图 | 98免费视频 | 国内老司机精品视频在线播出 | 久久偷拍人 | 欧美成人一区二区 | 99精品影视 | 白白国产永久免费视频 | 色多多幸福宝 | 亚洲AV无码乱码在线观看浪潮 | 大学生按摩黄a级中文片 | 欧美va在线播放免费观看 | 色老板在线免费视频 | 国产高清精品自在久久 | ipx-177绝对领域在线观看 |