AspectJ 入門(mén)

概述

在學(xué)習(xí)spring aop過(guò)程中呀打,發(fā)現(xiàn)有個(gè)怎么都繞不過(guò)去的坎肪虎,就是AspectJ的使用。少了這一部分哮幢,一些spring aop的源碼總覺(jué)得少了點(diǎn)什么带膀,看不大懂。所以接下來(lái)會(huì)寫(xiě)幾篇關(guān)于AspectJ的入門(mén)使用橙垢。

安裝示例代碼

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的安裝很簡(jiǎn)單嗽元,運(yùn)行 java -jar aspectj-1.9.2.jar 然后選下jdk路徑及最終aspectj要安裝(AspecJ安裝路徑)到哪里就好

3敛纲、安裝最后,會(huì)提示你要配置環(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还棱、編譯代碼示例

進(jìn)入 ${aspectJ 安裝路徑}/doc/examples
執(zhí)行 ajc -argfile telecom/billing.lst

5载慈、運(yùn)行示例

java telecom.BillingSimulation

6惭等、運(yùn)行結(jié)果


示例總結(jié)

簡(jiǎn)單總結(jié)下:
1)安裝配置aspectJ環(huán)境
2)使用 ajc -argfile 編譯類
3)運(yùn)行編譯后的字節(jié)碼

上述的例子是aspectJ 官方的例子 珍手,為了說(shuō)明如何使用aspectJ的使用,我們看另一個(gè)例子

另一個(gè)例子

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

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

我們先來(lái)看看原始類

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  + ")";
    }
}

再來(lái)看看一個(gè)隨著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é)果如下:


這里說(shuō)明一下幾點(diǎn):

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

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

切入點(diǎn)表達(dá)式

spring的切入點(diǎn)表達(dá)式我們非常熟悉,使用aspectJ時(shí)框喳,也需要配置切入點(diǎn)课幕,需要配置有哪些方法需要被切入

//表示Demo類的go方法調(diào)用過(guò)程中的方法需要被增強(qiáng)
pointcut goCut(): cflow(this(Demo) && execution(void go()));

//每一個(gè)Demo類定義的方法
pointcut demoExecs(): within(Demo) && execution(* *(..));

// 由于 goCut() 這個(gè)切入點(diǎn)還包含go()方法自己的調(diào)用,因此需要把自己給排掉
Object around(): demoExecs() && !execution(* go()) && goCut();

可能會(huì)問(wèn)五垮,既然為啥要同時(shí)配置
demoExecs() 以及 !execution(* go()) && goCut() 單獨(dú)有一個(gè)不夠么乍惊?

1)demoExecs()表示攔截Demo類的所有方法,如果不加后面的限制放仗,會(huì)同時(shí)攔截main方法润绎,以及go()方法
2)如果只有!execution(* go()) && goCut(),直接編譯時(shí)候會(huì)報(bào)錯(cuò)(warning)執(zhí)行后直接會(huì)報(bào)java.lang.StackOverflowError
3)如果只有!execution(* go()) && goCut()诞挨,可以執(zhí)行莉撇,但是只會(huì)攔截go方法

thisJoinPointStaticPart 和 thisJoinPoint

thisJoinPoint 包含了關(guān)于當(dāng)前切入點(diǎn)的一些信息(通過(guò)反射獲取的)
thisJoinPointStaticPart 包含一些靜態(tài)信息,參考官方文檔

通過(guò)配置切入點(diǎn)惶傻,我們實(shí)現(xiàn)了不改變Demo.java源碼的前提下棍郎,往Demo.java方法的前后插入了一段代碼。

與Spring 切面寫(xiě)法的對(duì)比

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

//聲明這是一個(gè)組件
@Component
//聲明這是一個(gè)切面Bean
@Aspect
@Slf4j
public class ServiceAspect {

    //配置切入點(diǎn),該方法無(wú)方法體,主要為方便同類中其他方法使用此處配置的切入點(diǎn)
    @Pointcut("execution(* com.hdj.learn.spring.aop.service..*(..))")
    public void aspect() {
    }

    /*
     * 配置前置通知,使用在方法aspect()上注冊(cè)的切入點(diǎn)
     * 同時(shí)接受JoinPoint切入點(diǎn)對(duì)象,可以沒(méi)有該參數(shù)
     */
    @Before("aspect()")
    public void before(JoinPoint joinPoint) {
        log.info("before " + joinPoint);
    }

    //配置后置通知,使用在方法aspect()上注冊(cè)的切入點(diǎn)
    @After("aspect()")
    public void after(JoinPoint joinPoint) {
        log.info("after " + joinPoint);
    }

    //配置環(huán)繞通知,使用在方法aspect()上注冊(cè)的切入點(diǎn)
    @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()上注冊(cè)的切入點(diǎn)
    @AfterReturning("aspect()")
    public void afterReturn(JoinPoint joinPoint) {
        log.info("afterReturn " + joinPoint);
    }

    //配置拋出異常后通知,使用在方法aspect()上注冊(cè)的切入點(diǎn)
    @AfterThrowing(pointcut = "aspect()", throwing = "ex")
    public void afterThrow(JoinPoint joinPoint, Exception ex) {
        log.info("afterThrow " + joinPoint + "\t" + ex.getMessage());
    }

}

其實(shí)非常類似坝撑,有切面、有通知粮揉、有目標(biāo)類等等巡李,切入點(diǎn)的表達(dá)式也非常類似。

總結(jié)下

初步了解了aspectJ的使用扶认,我們可以了解以下幾點(diǎn):
1)aspectJ的使用是在編譯期侨拦,通過(guò)特殊的編譯器可以在不改變代碼的前提下織入代碼(當(dāng)然能不能在運(yùn)行期,我還沒(méi)有確認(rèn))
2)aspectJ的使用辐宾,也是配置切入點(diǎn)狱从、通知

問(wèn)題

到了這里基本了解了aspectJ的使用膨蛮,但是還有幾個(gè)問(wèn)題。
1)我們?cè)趕pring中并沒(méi)有看到需要aspectj之類的關(guān)鍵詞季研,而是使用java代碼就可以了敞葛,這是如何做到的
2)同樣,我們也沒(méi)有使用特殊的編譯器
3)Spring源碼中與aspectJ 相關(guān)的AjType究竟是啥与涡?

這些問(wèn)題惹谐,我們會(huì)在下一篇博客里解決

10月份加班比較多,耽擱了寫(xiě)博客驼卖,這周開(kāi)始回復(fù)更新氨肌,會(huì)盡量補(bǔ)上上個(gè)月的。= = 雖然沒(méi)啥人看哈哈哈酌畜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末怎囚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子桥胞,更是在濱河造成了極大的恐慌恳守,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贩虾,死亡現(xiàn)場(chǎng)離奇詭異催烘,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)整胃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)颗圣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人屁使,你說(shuō)我怎么就攤上這事在岂。” “怎么了蛮寂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蔽午,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我酬蹋,道長(zhǎng)及老,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任范抓,我火速辦了婚禮骄恶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匕垫。我一直安慰自己僧鲁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著寞秃,像睡著了一般斟叼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上春寿,一...
    開(kāi)封第一講書(shū)人閱讀 50,050評(píng)論 1 291
  • 那天朗涩,我揣著相機(jī)與錄音,去河邊找鬼绑改。 笑死谢床,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绢淀。 我是一名探鬼主播萤悴,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瘾腰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼皆的!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蹋盆,我...
    開(kāi)封第一講書(shū)人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤费薄,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后栖雾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體楞抡,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年析藕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了召廷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡账胧,死狀恐怖竞慢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情治泥,我是刑警寧澤筹煮,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站居夹,受9級(jí)特大地震影響败潦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜准脂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一劫扒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狸膏,春花似錦沟饥、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)澎灸。三九已至,卻和暖如春遮晚,著一層夾襖步出監(jiān)牢的瞬間性昭,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工县遣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留糜颠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓萧求,卻偏偏與公主長(zhǎng)得像其兴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夸政,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理元旬,服務(wù)發(fā)現(xiàn),斷路器守问,智...
    卡卡羅2017閱讀 134,638評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,778評(píng)論 6 342
  • Install Google Chrome 幾個(gè)月前發(fā)布的Chrome 59 beta推出了headless模式匀归。...
    Shuangquan閱讀 8,163評(píng)論 1 5
  • 失落的婚姻(上) 在表姐姑姑的勸說(shuō)下,表姐似乎有些回心轉(zhuǎn)意耗帕。她覺(jué)得自己年齡不小了穆端,況且她和那個(gè)追求者只在好感階段,...
    雨晴天空閱讀 1,919評(píng)論 8 35
  • 1 2013、2014年的時(shí)候嗽仪,我與兩個(gè)男生關(guān)系曖昧荒勇。當(dāng)然是在不同的時(shí)期。 第一個(gè)男生是我隔壁宿舍的女孩給我介紹的...
    蓮葦閱讀 535評(píng)論 1 5