用了Spring很長時間了,一直想寫些AOP的東西,但一直沒有空閑,直到現在項目稍微進入正軌了,才趕緊寫寫。廢話不多說,先從AOP入門開始,后面再介紹AOP的原理(JDK動態代碼和CGLIB動態代碼的知識)。注:該部分適合於未接觸過Spring AOP的童鞋,如果是AOP老手,請直接繞過,不用打招呼^^
請尊重作者勞動成果,轉載請標明原文鏈接:
https://www.cnblogs.com/jpcflyer/p/9339104.html
一、環境准備
1.在Spring官網(地址見本文最后)下載springframework相關jar包,下載完后的jar包里面會包含aop/aspects/context/beans/core等相關的jar。
2.在AspectJ官網(AOP依賴包,地址見本文最后)下載AspectJ.jar,目前最新穩定版是1.9.1。
3.在Eclipse中,新建java project,然后在根目錄下新建lib目錄,並將第1步中下載的jar包全部copy到lib目錄下。
4.將第2步下載的AspectJ.jar解壓,並將解壓后的aspectjrt.jar、aspectjweaver.jar兩個jar包copy到lib目錄下。
5.項目右鍵-build path-libraries-add jars,然后選擇lib中的全部jar包,點擊確定。
6.在項目根目錄下新建配置文件applicationContext.xml,文件內容暫時為空,到此環境准備完畢。
二、代碼示例
了解AOP的童鞋都知道,使用AOP的方式有多少,這里建議使用配置文件的方式,能夠減少對代碼的注入,比較簡潔。
1.新建切面類

package test; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class AspectAdvice { /** * 前置通知 * * @param jp */
public void doBefore(JoinPoint jp) { System.out.println("===========進入before advice============ \n"); System.out.print("准備在" + jp.getTarget().getClass() + "對象上用"); System.out.print(jp.getSignature().getName() + "方法進行對 '"); System.out.print(jp.getArgs()[0] + "'進行刪除!\n\n"); System.out.println("要進入切入點方法了 \n"); } /** * 后置通知 * * @param jp * 連接點 * @param result * 返回值 */
public void doAfter(JoinPoint jp, String result) { System.out.println("==========進入after advice=========== \n"); System.out.println("切入點方法執行完了 \n"); System.out.print(jp.getArgs()[0] + "在"); System.out.print(jp.getTarget().getClass() + "對象上被"); System.out.print(jp.getSignature().getName() + "方法刪除了"); System.out.print("只留下:" + result + "\n\n"); } /** * 環繞通知 * * @param pjp * 連接點 */
public void doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("===========進入around環繞方法!=========== \n"); // 調用目標方法之前執行的動作
System.out.println("調用方法之前: 執行!\n"); // 調用方法的參數
Object[] args = pjp.getArgs(); // 調用的方法名
String method = pjp.getSignature().getName(); // 獲取目標對象
Object target = pjp.getTarget(); // 執行完方法的返回值:調用proceed()方法,就會觸發切入點方法執行
Object result = pjp.proceed(); System.out.println("輸出:" + args[0] + ";" + method + ";" + target + ";" + result + "\n"); System.out.println("調用方法結束:之后執行!\n"); } /** * 異常通知 * * @param jp * @param e */
public void doThrow(JoinPoint jp, Throwable e) { System.out.println("刪除出錯啦"); } }
2.新建業務類

package test; public class AspectBusiness { public String delete(String obj) { System.out.println("==========調用切入點:" + obj + "說:你敢刪除我!===========\n"); return obj + ":瞄~"; } public String add(String obj) { System.out.println("================這個方法不能被切。。。============== \n"); return obj + ":瞄~ 嘿嘿!"; } public String modify(String obj) { System.out.println("=================這個也設置加入切吧====================\n"); return obj + ":瞄改瞄啊!"; } }
3.在applicationContext.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" 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"
>
<!-- bean definitions here -->
<!-- 聲明一個業務類 -->
<bean id="aspectBusiness" class="test.AspectBusiness" />
<!-- 聲明通知類 -->
<bean id="aspectAdvice" class="test.AspectAdvice" />
<aop:config>
<aop:aspect id="businessAspect" ref="aspectAdvice">
<!-- 配置指定切入的對象 -->
<aop:pointcut id="point_cut" expression="execution(* test.*.*(..))" />
<!-- 只匹配add方法作為切入點 <aop:pointcut id="except_add" expression="execution(* test.*.add(..))" />
-->
<!-- 前置通知 -->
<aop:before method="doBefore" pointcut-ref="point_cut" />
<!-- 后置通知 returning指定返回參數 -->
<aop:after-returning method="doAfter" pointcut-ref="point_cut" returning="result" />
<aop:around method="doAround" pointcut-ref="point_cut"/>
<aop:after-throwing method="doThrow" pointcut-ref="point_cut" throwing="e"/>
</aop:aspect>
</aop:config>
</beans>
4.新建測試類

package test; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class StringTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AspectBusiness business = (AspectBusiness) context.getBean("aspectBusiness"); business.delete("貓"); } }
三、運行結果
運行結果如下所示:
===========進入before advice============ 准備在class test.AspectBusiness對象上用delete方法進行對 '貓'進行刪除! 要進入切入點方法了 ===========進入around環繞方法!=========== 調用方法之前: 執行! ==========調用切入點:貓說:你敢刪除我!=========== 輸出:貓;delete;test.AspectBusiness@3b69e7d1;貓:瞄~ 調用方法結束:之后執行! ==========進入after advice=========== 切入點方法執行完了 貓在class test.AspectBusiness對象上被delete方法刪除了只留下:null
這樣AOP的示例就算完成了,本篇先不介紹切面、通知、切入點等的相關概念了,這些概念在百度上可謂信手拈來,如果有不了解,可以自行百度。本篇先寫到這里,后續再介紹AOP的相關原理。
參考資料:
1. Spring官網:https://spring.io/
2. Spring5.0官網下載地址:https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework/spring/5.0.0.RELEASE
3. AspectJ最新穩定版官網下載地址:http://www.eclipse.org/aspectj/downloads.php#stable_release