日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java切面类关键字_AspectJ 入门

發(fā)布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java切面类关键字_AspectJ 入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

概述

在學(xué)習(xí)spring aop過程中,發(fā)現(xiàn)有個怎么都繞不過去的坎,就是AspectJ的使用。少了這一部分,一些spring aop的源碼總覺得少了點什么,看不大懂。所以接下來會寫幾篇關(guān)于AspectJ的入門使用。

安裝示例代碼

1、首先,下載最新的穩(wěn)定版本(我自己下的是AspectJ 1.9.2, Released 24 Oct 2018 版本)aspectj-1.9.2.jar

http://www.eclipse.org/aspectj/downloads.php#stable_release

2、安裝

aspectJ的安裝很簡單,運行 java -jar aspectj-1.9.2.jar 然后選下jdk路徑及最終aspectj要安裝(AspecJ安裝路徑)到哪里就好

3、安裝最后,會提示你要配置環(huán)境變量了

按照環(huán)境配下PATH變量 和 CLASSPATH變量就好

export PATH=${JAVA_HOME}/bin:$PATH:/Users/hdj/software/aspectj/bin

export CLASSPATH=${CLASSPATH}:/Users/hdj/software/aspectj/lib/aspectjrt.jar

4、編譯代碼示例

進入 ${aspectJ 安裝路徑}/doc/examples

執(zhí)行 ajc -argfile telecom/billing.lst

5、運行示例

java telecom.BillingSimulation

6、運行結(jié)果

示例總結(jié)

簡單總結(jié)下:

1)安裝配置aspectJ環(huán)境

2)使用 ajc -argfile 編譯類

3)運行編譯后的字節(jié)碼

上述的例子是aspectJ 官方的例子 ,為了說明如何使用aspectJ的使用,我們看另一個例子

另一個例子

知道如何運行aspectJ給的官方示例后,我們繼續(xù)學(xué)習(xí)官網(wǎng)給的另一個例子,例子路徑

${aspectJ 路徑}/doc/examples/tjp/Demo.java

我們先來看看原始類

public class Demo {

static Demo d;

public static void main(String[] args){

new Demo().go();

}

void go(){

d = new Demo();

//調(diào)用foo方法

d.foo(1,d);

//調(diào)用bar方法

System.out.println(d.bar(new Integer(3)));

}

void foo(int i, Object o){

//打印foo

System.out.println("Demo.foo(" + i + ", " + o + ")\n");

}

String bar (Integer j){

System.out.println("Demo.bar(" + j + ")\n");

return "Demo.bar(" + j + ")";

}

}

再來看看一個隨著Demo.java一起被 ajc編譯的特殊的類GetInfo.java:

package tjp;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.reflect.CodeSignature;

aspect GetInfo {

static final void println(String s){ System.out.println(s); }

pointcut goCut(): cflow(this(Demo) && execution(void go()));

pointcut demoExecs(): within(Demo) && execution(* *(..));

Object around(): demoExecs() && !execution(* go()) && goCut() {

println("Intercepted message: " +

thisJoinPointStaticPart.getSignature().getName());

println("in class: " +

thisJoinPointStaticPart.getSignature().getDeclaringType().getName());

printParameters(thisJoinPoint);

println("Running original method: \n" );

Object result = proceed();

println(" result: " + result );

return result;

}

// 打印參數(shù)

static private void printParameters(JoinPoint jp) {

println("Arguments: " );

Object[] args = jp.getArgs();

String[] names = ((CodeSignature)jp.getSignature()).getParameterNames();

Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes();

for (int i = 0; i < args.length; i++) {

println(" " + i + ". " + names[i] +

" : " + types[i].getName() +

" = " + args[i]);

}

}

}

這里和spring aop的使用很多方面非常類似,最后執(zhí)行的結(jié)果如下:

這里說明一下幾點:

GetInfo.java 含有的特殊關(guān)鍵詞

GetInfo.java含有很多特殊的關(guān)鍵詞,這些關(guān)鍵詞java是無法識別的,需要通過ajc編譯才能織入到字節(jié)碼中

切入點表達式

spring的切入點表達式我們非常熟悉,使用aspectJ時,也需要配置切入點,需要配置有哪些方法需要被切入

//表示Demo類的go方法調(diào)用過程中的方法需要被增強

pointcut goCut(): cflow(this(Demo) && execution(void go()));

//每一個Demo類定義的方法

pointcut demoExecs(): within(Demo) && execution(* *(..));

// 由于 goCut() 這個切入點還包含go()方法自己的調(diào)用,因此需要把自己給排掉

Object around(): demoExecs() && !execution(* go()) && goCut();

可能會問,既然為啥要同時配置

demoExecs() 以及 !execution(* go()) && goCut() 單獨有一個不夠么?

1)demoExecs()表示攔截Demo類的所有方法,如果不加后面的限制,會同時攔截main方法,以及go()方法

2)如果只有!execution(* go()) && goCut(),直接編譯時候會報錯(warning)執(zhí)行后直接會報java.lang.StackOverflowError

3)如果只有!execution(* go()) && goCut(),可以執(zhí)行,但是只會攔截go方法

thisJoinPointStaticPart 和 thisJoinPoint

thisJoinPoint 包含了關(guān)于當(dāng)前切入點的一些信息(通過反射獲取的)

thisJoinPointStaticPart 包含一些靜態(tài)信息,參考官方文檔

通過配置切入點,我們實現(xiàn)了不改變Demo.java源碼的前提下,往Demo.java方法的前后插入了一段代碼。

與Spring 切面寫法的對比

對比下之前在學(xué)習(xí)Spring時候,配置的切面

//聲明這是一個組件

@Component

//聲明這是一個切面Bean

@Aspect

@Slf4j

public class ServiceAspect {

//配置切入點,該方法無方法體,主要為方便同類中其他方法使用此處配置的切入點

@Pointcut("execution(* com.hdj.learn.spring.aop.service..*(..))")

public void aspect() {

}

/*

* 配置前置通知,使用在方法aspect()上注冊的切入點

* 同時接受JoinPoint切入點對象,可以沒有該參數(shù)

*/

@Before("aspect()")

public void before(JoinPoint joinPoint) {

log.info("before " + joinPoint);

}

//配置后置通知,使用在方法aspect()上注冊的切入點

@After("aspect()")

public void after(JoinPoint joinPoint) {

log.info("after " + joinPoint);

}

//配置環(huán)繞通知,使用在方法aspect()上注冊的切入點

@Around("aspect()")

public void around(JoinPoint joinPoint) {

long start = System.currentTimeMillis();

try {

((ProceedingJoinPoint) joinPoint).proceed();

long end = System.currentTimeMillis();

log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");

} catch (Throwable e) {

long end = System.currentTimeMillis();

log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());

}

}

//配置后置返回通知,使用在方法aspect()上注冊的切入點

@AfterReturning("aspect()")

public void afterReturn(JoinPoint joinPoint) {

log.info("afterReturn " + joinPoint);

}

//配置拋出異常后通知,使用在方法aspect()上注冊的切入點

@AfterThrowing(pointcut = "aspect()", throwing = "ex")

public void afterThrow(JoinPoint joinPoint, Exception ex) {

log.info("afterThrow " + joinPoint + "\t" + ex.getMessage());

}

}

其實非常類似,有切面、有通知、有目標(biāo)類等等,切入點的表達式也非常類似。

總結(jié)下

初步了解了aspectJ的使用,我們可以了解以下幾點:

1)aspectJ的使用是在編譯期,通過特殊的編譯器可以在不改變代碼的前提下織入代碼(當(dāng)然能不能在運行期,我還沒有確認)

2)aspectJ的使用,也是配置切入點、通知

問題

到了這里基本了解了aspectJ的使用,但是還有幾個問題。

1)我們在spring中并沒有看到需要aspectj之類的關(guān)鍵詞,而是使用java代碼就可以了,這是如何做到的

2)同樣,我們也沒有使用特殊的編譯器

3)Spring源碼中與aspectJ 相關(guān)的AjType究竟是啥?

這些問題,我們會在下一篇博客里解決

10月份加班比較多,耽擱了寫博客,這周開始回復(fù)更新,會盡量補上上個月的。= = 雖然沒啥人看哈哈哈。

總結(jié)

以上是生活随笔為你收集整理的java切面类关键字_AspectJ 入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。