網上不少人在介紹AOP時都這樣說:面向切面編程,經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。我的認爲這句話是錯誤。AOP和OOP同樣,是一種程序設計思想,而非技術手段。javascript
程序設計有六大原則,其中第一原則就是單一職責原則。意思就是一個類只負責一件事情。這與OOP的封裝特性相得益彰。在這個條件下,咱們的程序會被分散到不一樣的類、不一樣的方法中去。這樣作的好處是下降了類的複雜性,提升了程序的可維護性。可是同時,它也使代碼變得囉嗦了。例如,咱們要爲方法添加調用日誌,那就必須爲全部類的全部方法添加日誌調用,儘管它們都是相同的。爲了解決上述問題,AOP應運而生了。html
AOP旨在將橫切關注點與業務主體進行分類,從而提升程序代碼的模塊化程度。橫切關注點是一個抽象的概念,它是指那些在項目中貫穿多個模塊的業務。上個例子中日誌功能就是一個典型的橫切關注點。java
動態代理是一種設計模式。它有如下特徵:android
如下面這個例子爲例,咱們看一下動態代理的類圖結構。git
一般咱們的APP都有一部分功能要求用戶登陸以後才能訪問。如修改密碼、修改用戶名等功能。當用戶打算使用這些功能時,咱們通常要對用戶的登陸狀態進行判斷,只有用戶登陸了,才能正常使用這些功能。而若是用戶未登陸,咱們的APP要跳轉到登陸頁。就以修改密碼爲例咱們看一下動態代理的類圖。github
InvocationHandler是Java JDK提供的動態代理的入口,用來對被代理對象的方法作處理。編程
代碼以下:設計模式
public static class LoginCheckHandler implements InvocationHandler {
private static <S, T extends S> T proxy(S source, Class<T> tClass) {
return (T) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{tClass}, new LoginCheckHandler(source));
}
private Object mSource;
LoginCheckHandler(Object source) {
this.mSource = source;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(!checkLogin()){
jumpToLoginActivity();
return null;
}
return method.invoke(mSource, args);
}
private boolean checkLogin(){
System.out.println("用戶未登陸");
return false;
}
private void jumpToLoginActivity(){
System.out.println("跳轉到登陸頁");
}
}
public class Client {
public static void main(String[] args) {
IUserSetting source = new UserSetting();
IUserSetting iUserSetting = LoginCheckHandler.proxy(source,IUserSetting.class);
iUserSetting.changePwd("new Password");
}
}
複製代碼
通過這樣封裝以後,檢查登陸跳轉登陸頁的邏輯做爲橫切關注點就和業務主體進行了分離。當有新的需求須要登陸檢查時,咱們只須要經過LoginCheckHandler生成新的代理對象便可。api
APT(Annotation Processing Tool)是一種編譯期註解處理技術。它經過定義註解和處理器來實現編譯期生成代碼的功能,而且將生成的代碼和源代碼一塊兒編譯成.class文件。經過APT技術,咱們將橫切關注點封裝到註解處理器中,從而實現橫切關注點與業務主體的分離。更詳細的介紹請移步Android編譯期插樁,讓程序本身寫代碼(一)。服務器
AspectJ就是一種編譯器,它在Java編譯器的基礎上增長了關鍵字識別和編譯方法。所以,AspectJ能夠編譯Java代碼。它還提供了Aspect程序。在編譯期間,將開發者編寫的Aspect程序織入到目標程序中,擴展目標程序的功能。開發者經過編寫AspectJ程序實現AOP功能。更詳細的介紹請移步Android編譯期插樁,讓程序本身寫代碼(二)。
Transform是Android Gradle提供的,能夠操做字節碼的一種方式。App編譯時,源代碼首先會被編譯成class,而後再被編譯成dex。在class編譯成dex的過程當中,會通過一系列Transform
處理。Javassist/ASM是一個可以很是方便操做字節碼的庫。咱們經過它們能夠修改編譯的.class文件。利用這種方式,咱們將橫切關注點封裝到Transform,來達到與業務主體分離的目的。更詳細的介紹請移步Android編譯期插樁,讓程序本身寫代碼(三)。
利用AOP能夠作一些頗有意思的事情。一些知名的開源框架,他們都採用了AOP的思想。例如:ButterKnife、Retrofit、Hugo等。另外,AOP在性能檢測和埋點技術上出現了百家爭鳴的局面。
除此以外,藉助AOP咱們還能夠實現如下功能:
一般咱們在向服務器請求數據時,會顯示一個Loding,等到結果返回後再隱藏它。咱們能夠經過AOP技術把顯示、隱藏Loding的動做和業務主體分離開。
權限管理。給你們推薦一個開源庫Aopermission,用AspectJ解決了權限問題。