初窺AspectJ

來源:互聯網
上載者:User

標籤:相對   處理   pid   success   很多   utf-8   roc   enter   需要   

AspectJ可以說是Java中當之無愧的黑魔法。說它是黑魔法,一方面是因為它很強大,能夠解決一些傳統編程方法論解決不了的問題,而另一方面,它也相當的晦澀,有著比較陡峭的學習曲線。

本文將帶大家探索下AspectJ是什麼,能做什麼,以及如何來做,希望通過本文能夠讓大家初窺AspectJ之門道

AOP是什麼

相信很多人第一次聽說AOP是在學習spring的時候,筆者也是。這個概念其實困擾了我很久,到底是AOP?AOP是Aspect Oriented Programming的縮寫,和OOP(Object Oriented Programming)一樣,都代表一種編程思想。不同的是,OOP是對世界萬物的抽象,而AOP做的則是對業務處理過程的抽象,一定程度上說,AOP是OOP思想的一種延續,對程式進行了進一步的封裝。

那麼AOP到底能夠解決什麼問題呢?以在現有系統上增加一個安全性原則為例,我們需要在各個模組的代碼中不同地方添加代碼,進行安全性原則的檢查。這種方式實現起來很複雜,容易出錯,而且沒法複用。這裡描述的安全問題就是一個橫切關注點問題,開發人員需要找到所有需要關注的代碼斷,在現有代碼中間插入新的業務代碼(就好像對現有代碼做了切分)。類似這裡安全性原則的問題還有很多,比如tracing等。

AspectJ基本概念

AspectJ是AOP的Java實現版本,定義了AOP的文法,可以說是對Java的一個擴充。相對於Java,AspectJ引入了join point(連接點)的概念,同時引入三個新的結構,pointcut(切點), advice(通知),inter-type declaration(跨型別宣告)以及aspect。其中pointcut和advice是AspectJ中動態額部分,用來指定在什麼條件下切斷執行,以及採取什麼動作來實現切面操作。顧名思義,這裡的pointcut就是用來定義什麼情況下進行橫切,而advice則是指橫切情況下我們需要做什麼操作,所以說pointcut和advice會動態影響程式的運行流程。從某種角度上說,pointcut(切點)和我們平時用IDE偵錯工具時打的斷點很類似,當程式執行到我們打的斷點的地方的時候(運行到滿足我們定義的pointcut的語句的時候,也就是join point連接點),我們可以執行一段指令碼(執行advice中定義的行為)。

而AspectJ中的inter-type declaration(跨型別宣告)則是AspectJ中靜態部分,它影響的是程式的靜態結構,比如成員變數,類之間的關係等。Aspect則是對前三個結構的封裝,類似於java中的類。

第一個AspectJ程式

這裡我們先不去具體探討AspectJ的文法問題,而重點關注如何用AspectJ寫一個簡單的Demo。這裡我用的開發環境是IntelliJ,且項目使用maven來構建。

maven依賴

要運行AspectJ程式,首先要引入AspectJ運行時的依賴:

<!--aspectj runtime classes --><dependency>    <groupId>org.aspectj</groupId>    <artifactId>aspectjrt</artifactId>    <version>1.8.9</version></dependency>

除了運行時依賴,還需要aspectjweaver.jar

<!--to introduce aspect to java class in load time--><dependency>    <groupId>org.aspectj</groupId>    <artifactId>aspectjweaver</artifactId>    <version>1.8.9</version></dependency>
一個簡單的類

先寫一個簡單的類:

package cc.databus.aspect;public class Account {    double balance = 200;    public boolean withdraw(int amount) {        if (balance < amount) {            return false;        }        balance = balance - amount;        return true;    }    @Override    public String toString() {        return "Account{" +                "balance=" + balance +                ‘}‘;    }}

該類定義了一個Account類,並提供了withdraw(取款)的方法。

aspect定義

建立一個AccountAspect.aj檔案來記錄取款前後的資訊:

// aspect package cc.databus.aspect;public aspect AccountAspect {    // define a pointcut to pick up invoking Accont.withdraw     pointcut callWithDraw(int amount, Account account):            call(boolean Account.withdraw(int))             && args(amount)             && target(account);    // advice definition executing before enterring method body    before(int amount, Account acc): callWithDraw(amount, acc) {        System.out.println("Start withdraw " + amount + " from " + acc);    }    after(int amount, Account acc) returning (Object ret): callWithDraw(amount, acc) {        System.out.print("Finish withdraw, return "         + ret +", account after withdraw is: " +  acc);    }}

通過IntelliJ可以很方便的建立aspect檔案,在包上面右鍵->New->Aspect:

正如你所見,上面的AccountAspect.aj定義了AspectJ的pointcut,advice以及aspect。

aspect織如(weaving)

Weaving....很奇怪的詞。。。這裡指的是將aspect中定義的advice植入到運行時的過程。這裡我們使用一個maven外掛程式來講aspect織如,這個外掛程式是Mojo AspectJ Maven Plugin:

<plugins>    <plugin>        <groupId>org.codehaus.mojo</groupId>        <artifactId>aspectj-maven-plugin</artifactId>        <version>1.7</version>        <configuration>            <complianceLevel>1.8</complianceLevel>            <source>1.8</source>            <target>1.8</target>            <showWeaveInfo>true</showWeaveInfo>            <verbose>true</verbose>            <encoding>utf-8</encoding>        </configuration>        <executions>            <execution>                <goals>                    <!--use this goal to weave all your main classes-->                    <goal>compile</goal>                    <!--use this goal to weave all your test classes-->                    <goal>test-compile</goal>                </goals>            </execution>        </executions>    </plugin></plugins>

OK,下面我們寫一個UT來測試下aspect是否生效了:

import cc.databus.aspect.Account;import org.junit.Before;import org.junit.Test;import static org.junit.Assert.assertFalse;import static org.junit.Assert.assertTrue;public class TestAccount {    private Account account;    @Before    public void before() {        account = new Account();    }    @Test    public void given20AndMin10_whenWithdraw5_thenSuccess() {        assertTrue(account.withdraw(5));    }        @Test    public void given20AndMin10_whenWithdraw100_thenFail() {        assertFalse(account.withdraw(100));    }}

運行測試,如果命令列有如下的輸出,則表示aspect成功織入我們的代碼,並且pointcut成功切入了Account.withdraw的調用:

Start withdraw 5 from Account{balance=200.0}Finish withdraw, return true, account after withdraw is: Account{balance=195.0}Process finished with exit code 0
總結

總的來說,AspectJ是一個相當晦澀難懂的技術,但是不得不承認它很強大。本文在從理論出發,先介紹AOP以及AspectJ的基本概念,然後以一個簡單的Demo程式介紹了如何在項目中使用AspectJ。

文章同步發布在我的個人部落格https://jianyuan.me上,歡迎拍磚。
傳送門: 初窺AspectJ

初窺AspectJ

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.