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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

AOP概述及实现原理

發(fā)布時間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AOP概述及实现原理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

AOP

引言

Spring 為解耦而生,其中AOP(面向切面編程)是很濃重的一筆。AOP(Aspect-Oriented-Programming)指一種程序設(shè)計范型,該范型以一種稱為切面(aspect)的語言構(gòu)造為基礎(chǔ),切面是一種新的模塊化機制,用來描述分散在對象、類或方法中的橫切關(guān)注點(crosscutting)。

AOP相關(guān)概念

  • 連接點(JoinPoint):程序執(zhí)行到某個特定位置(如:某個方法調(diào)用前,調(diào)用后,方法拋出異常),一個類或一段程序代碼擁有一些具有邊界性質(zhì)的特定點,這些代碼中的特定點就是連接點。
  • 切點(PointCut):如果連接點相當(dāng)于數(shù)據(jù)中的記錄,那么切點就相當(dāng)于查詢條件,一個切點可以匹配多個連接點。SpringAop的規(guī)則解析引擎負責(zé)解析切點所設(shè)定的查詢條件,找到對應(yīng)的連接點。
  • 增強(Advice):增強是織入到目標(biāo)類連接點上的一段程序代碼,Spring提供的增強接口都是帶方位的,如BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。,很多資料上將增強譯為“通知”,這明顯是詞不達意的。

說明:Advice在國內(nèi)很多的書面資料上都被翻譯為“通知”,但這個翻譯無法表達其本質(zhì),有少量的讀物將這個詞翻譯為“增強”,這個翻譯是比較為準(zhǔn)確的詮釋,我們通過AOP將橫切關(guān)注功能加到原有的業(yè)務(wù)邏輯上,這就是對原有的業(yè)務(wù)邏輯進行的一種增強,這個增強可以是前置增強,后置增強,返回后增強,拋出異常時增強,和包圍型增強。

  • 引介(Introduction):引介是一種特殊的增強,他為類添加一些屬性和方法,這樣,即使一個業(yè)務(wù)類原本沒有實現(xiàn)某個接口,通過引介功能,可以動態(tài)的為該業(yè)務(wù)類添加接口的實現(xiàn)邏輯,讓業(yè)務(wù)類稱為這個接口的實現(xiàn)類
  • 織入(Weaving):織入是將增強添加到目標(biāo)類具體連接點上的過程,AOP由三種織入方式:1 編譯期織入:需要特殊的Java編譯期(例如Aspect的ajc);2 裝載期織入:要求使用特殊的類加載器,在裝載類的時候?qū)︻愡M行增強,3 運行時織入:在運行時為目標(biāo)類生成代理實現(xiàn)增強。Spring采用動態(tài)代理的方式事實現(xiàn)了運行時織入,而AspectJ采用了編譯期織入和裝載期織入的方式。
  • 切面(Aspect):切面是由切點和增強(引介)組成的,它包括了對橫切關(guān)注功能的定義,也包括了對連接點的定義。

原理

AOP是運用了動態(tài)代理。代理模式是GoF提出的23種設(shè)計模式中最為經(jīng)典的模式之一,代理是對象的結(jié)構(gòu)模式,他給某一個對象提供一個對象代理,并由代理控制對原對象的引用,簡單的說,代理對象可以完成比原對象更多的職責(zé),當(dāng)需要為原對象添加橫切關(guān)注功能時,就可以使用原對象的代理對象。我們在打開Office系列的Word文檔時,如果文檔中有插圖,當(dāng)文檔剛加載時,文檔中的插圖都只是一個虛框的占位符,等真正用戶翻到某一頁要查看該圖片時,才會真正加載這張圖片,這其實就是代理模式的使用,代替真正的虛框就是一個虛擬代理,Hibernate的load方法也是返回一個虛擬代理對象,等真正用戶需要訪問對象的屬性時,才向數(shù)據(jù)庫發(fā)出SQL語句。

按照代理創(chuàng)建初期,代理可以分為兩種:

  • 靜態(tài)代理:由程序員創(chuàng)建或特定工具自動生成源代碼,再對其編譯,在程序運行前,代理類的.class文件就已經(jīng)存在了。
  • 動態(tài)代理:在程序運行時,運行反射機制動態(tài)創(chuàng)建而成 另外還有CGLib動態(tài)代理,它是針對類實現(xiàn)的代理。

實現(xiàn)

JDK代理

靜態(tài)代理

下面用一個找槍手代考的例子演示代理模式的使用

package com.test.test2.interfaces;/*** @Author: Young* @QQ: 403353323* @Date: 2019/4/25 10:35*/ public interface Candidate {public void answerTheQuestion(); }復(fù)制代碼package com.test.test2;import com.test.test2.interfaces.Candidate;/*** @Author: Young* @QQ: 403353323* @Date: 2019/4/25 10:36*/ public class LazyStudent implements Candidate {private String name;public LazyStudent(String name) {this.name = name;}@Overridepublic void answerTheQuestion() {// 懶學(xué)生只能寫出自己名字不會答題System.out.println("姓名" + name);} }復(fù)制代碼package com.test.test2;import com.test.test2.interfaces.Candidate;/*** @Author: Young* @QQ: 403353323* @Date: 2019/4/25 10:40*/ public class Gunman implements Candidate {private Candidate target; //被代理的對象public Gunman(Candidate target) {this.target = target;}@Overridepublic void answerTheQuestion() {// 搶手要寫上代考學(xué)生的名字target.answerTheQuestion();// 搶手幫助懶學(xué)生答題并交卷System.out.println("奮筆疾書書寫正確答案");System.out.println("交卷");} }復(fù)制代碼@Test public void testGunman(){Candidate c = new Gunman(new LazyStudent("王小二"));c.answerTheQuestion(); } 復(fù)制代碼

觀察代理可以發(fā)現(xiàn)每一個代理類只能為一個接口服務(wù),這樣一來程序開發(fā)中必然會產(chǎn)生很多的代理,而且,所有代理除了調(diào)用方法不一樣之外,其他操作都一樣,則此時肯定是重復(fù)代碼,解決這一個問題最好的做法是通過一個代理類完成全部的代理功能,那么此時就必須使用動態(tài)代理了。

動態(tài)代理

從JDK 1.3 開始,Java提供了動態(tài)技術(shù),動態(tài)代理類的字節(jié)碼在程序運行時由Java反射機制動態(tài)生成,無需程序員手工編寫它的源代碼。動態(tài)代理類不僅簡化了編程工作,而且提高了軟件系統(tǒng)的可擴展性,因為反射機制可以生成任意類型的動態(tài)代理。

java.lang.reflect包中的Proxy類和InvocationHandler接口提供了生成動態(tài)代理的能力。

JDK動態(tài)代理中包含一個接口和一個類:

  • InvocationHandler接口
public interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable; } 復(fù)制代碼

參數(shù)說明:

參數(shù)說明
Object proxy指被代理的對象
Method method要調(diào)用的方法
Object[] args方法調(diào)用時的參數(shù)

可以將InvocationHandler接口的子類想象成一個代理的最終操作類,替換掉ProxySubject。

  • Proxy類:
  • Proxy類是專門完成代理的操作類,可以通過此類為一個或多個接口動態(tài)生成實現(xiàn)類,此類提供了如下的操作方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{/***************具體內(nèi)容略去****************/} 復(fù)制代碼

參數(shù)說明:

源碼中的參數(shù)說明

* @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class to implement * @param h the invocation handler to dispatch method invocations to 復(fù)制代碼參數(shù)說明
ClassLoader類加載器
Class<?>[] interfaces得到全部的接口
InvocationHandler h得到InvocationHandler接口的子類實例

Ps:在Proxy中類的newProxyInstance()方法中需要一個ClassLoader類的實例,ClassLoader實際上對應(yīng)的是類加載器。在Java中主要有三種類加載器:

  • Bootstrap ClassLoader:此口加載器采用C++編寫,一般開發(fā)中是看不到的。
  • Extendsion ClassLoader:用來進行擴展類的加載器,一般對應(yīng)的是jre\lib\ext目錄中的類;
  • APPClassLoader:(默認)加載classpath制定的類,是最常使用的一種加載器。

BookFacade.java

public interface BookFacade { public void addBook(); } 復(fù)制代碼

BookFacadeImpl.java

import net.battier.dao.BookFacade; public class BookFacadeImpl implements BookFacade { @Override public void addBook() { System.out.println("增加圖書方法。。。"); } } 復(fù)制代碼

BookFacadeProxy.java

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK動態(tài)代理代理類 */ public class BookFacadeProxy implements InvocationHandler { private Object target; /** * 綁定委托對象并返回一個代理類 * @param target * @return */ public Object bind(Object target) { this.target = target; //取得代理對象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷) } @Override /** * 調(diào)用方法 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=null; System.out.println("事物開始"); //執(zhí)行方法 result=method.invoke(target, args); System.out.println("事物結(jié)束"); return result; } } 復(fù)制代碼

TestProxy.java

import net.battier.dao.BookFacade; import net.battier.dao.impl.BookFacadeImpl; import net.battier.proxy.BookFacadeProxy; public class TestProxy { public static void main(String[] args) { BookFacadeProxy proxy = new BookFacadeProxy(); BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl()); bookProxy.addBook(); } } 復(fù)制代碼

說明:使用Java的動態(tài)代理有一個局限性就是被代理的類必須實現(xiàn)接口(也就是說只能對該類所實現(xiàn)接口中定義的方法進行代理),雖然面向接口編程是每個優(yōu)秀的Java程序員都知道的規(guī)則,但現(xiàn)實往往不盡人意,對于沒有實現(xiàn)接口的代理類如何為其生成代理類呢?繼承繼承是最經(jīng)典的擴展已有代碼能力的手段。CGLib代理就是這樣實現(xiàn)代理。

CGLib動態(tài)代理

CGLib采用非常底層的字節(jié)碼生成技術(shù),通過為一個類創(chuàng)建子類來生成代理類,它彌補了Java動態(tài)代理的不足,因此,Spring中的動態(tài)代理和CGLib都是創(chuàng)建代理的重要手段,對于實現(xiàn)了接口的類就用動態(tài)代理為其生成代理類,而沒有實現(xiàn)接口的類就用CGLib通過繼承方式為其創(chuàng)建代理類。但因為采用的是繼承,所以不能對final修飾的類進行代理。

intercept參數(shù)列表:

參數(shù)說明
Object obj代理的對象
Metho method表示攔截的方法
Object[] args數(shù)組表示參數(shù)列表,基本數(shù)據(jù)類型需要傳入其包裝類型,如int-->Integer、long-Long、double-->Double
MethodProxy methodProxy表示對方法的代理,invokeSuper方法表示對被代理對象方法的調(diào)用
package com.test.test2.proxy;/*** @Author: Young* @QQ: 403353323* @Date: 2019/5/3 21:32*/ public class BookFacadeImpl1 {public void addBook(){System.out.println("增加圖書的普通方法");} } 復(fù)制代碼package com.test.test2.proxy;import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;/*** @Author: Young* @QQ: 403353323* @Date: 2019/5/3 21:34*//*** CGLib創(chuàng)建動態(tài)代理*/ public class BookFacadeProxy implements MethodInterceptor {private Object target;public Object getInstance(Object target){this.target = target;Enhancer enhancer = new Enhancer();enhancer.setSuperclass(this.target.getClass());// 回調(diào)方法enhancer.setCallback(this);//創(chuàng)建代理對象return enhancer.create();}@Override// 回調(diào)方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("開始事務(wù)");methodProxy.invokeSuper(obj, args);System.out.println("事務(wù)結(jié)束");return null;} }復(fù)制代碼public class TestCglib { public static void main(String[] args) { BookFacadeCglib cglib=new BookFacadeCglib(); BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); bookCglib.addBook(); } } 復(fù)制代碼
參考

AOP實現(xiàn)原理
Java面試知識點總結(jié)及解析
java動態(tài)代理(JDK和cglib)
Cglib及其基本使用

總結(jié)

以上是生活随笔為你收集整理的AOP概述及实现原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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