AOP與OOP有什么區別,談談AOP的原理是什么 [復制鏈接]

2019-8-29 09:49
liujh 閱讀:662 評論:0 贊:0
Tag:  AOP OOP

面試官: 你知道什么是AOP嗎?AOP與OOP有什么區別,談談AOP的原理是什么

心理分析:一旦問到aop面試官在開發自己的項目中 肯定是用到了aop切面編程的。這個時候求職者需要格外注意,特別是aop 在編譯時的性能優勢,apk編譯的原理講起。切勿將aop的概念弄混,一定要將oop面向對象與aop面向切面的場景說出來

求職者: aop實現的三大方式(反射 (xutil) apt注解(ButterKnife) aspect (本文即將講到的)) 說出各自的優缺點

一、AOP概念

百度百科中對AOP的解釋如下: 在軟件業,AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。

AOP是OOP的延續,是軟件開發中的一個熱點,也是很多框架如 java中的Spring框架中的一個重要內容,是函數式編程的一種衍生范型。 利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。

AOP只是一種思想的統稱,實現這種思想的方法有挺多。AOP通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,提高開發效率。

(1)AOP與OOP的關系

**OOP(面向對象編程)**針對業務處理過程的實體及其屬性和行為進行抽象封裝,以獲得更加清晰高效的邏輯單元劃分。但是也有它的缺點,最明顯的就是關注點聚焦時,面向對象無法簡單的解決這個問題,一個關注點是面向所有而不是單一的類,不受類的邊界的約束,因此OOP無法將關注點聚焦來解決,只能分散到各個類中。 AOP(面向切面編程)則是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。這兩種設計思想在目標上有著本質的差異。 AOP并不是與OOP對立的,而是為了彌補OOP的不足。OOP解決了豎向的問題,AOP則解決橫向的問題。因為有了AOP我們的調試和監控就變得簡單清晰。

簡單的來講,AOP是一種:可以在不改變原來代碼的基礎上,通過“動態注入”代碼,來改變原來執行結果的技術。

(2)AOP主要應用場景

日志記錄,性能統計,安全控制,事務處理,異常處理等等。

(3)主要目標

將日志記錄,性能統計,安全控制,事務處理,異常處理等代碼從業務邏輯代碼中劃分出來,通過對這些行為的分離,我們希望可以將它們獨立到非指導業務邏輯的方法中,進而改變這些行為的時候不影響業務邏輯的代碼。

上圖是一個APP模塊結構示例,按照照OOP的思想劃分為“視圖交互”,“業務邏輯”,“網絡”等三個模塊,而現在假設想要對所有模塊的每個方法耗時(性能監控模塊)進行統計。這個性能監控模塊的功能就是需要橫跨并嵌入眾多模塊里的,這就是典型的AOP的應用場景。

AOP的目標是把這些橫跨并嵌入眾多模塊里的功能(如監控每個方法的性能) 集中起來,放到一個統一的地方來控制和管理。如果說,OOP如果是把問題劃分到單個模塊的話,那么AOP就是把涉及到眾多模塊的某一類問題進行統一管理。

對比:

功能OOPAOP增加日志所有功能模塊單獨添加,容易出錯能夠將同一個關注點聚焦在一處解決修改日志功能代碼分散,不方便調試能夠實現一處修改,處處生效

例如:在不改變 main 方法的同時通過代碼注入的方式達到目的

/**
* Before
*/
public class Test {
public static void main(String[] args) {
// do something
}
}
/**
* After
*/
public class Test {
public static void main(String[] args) {
long start = System.currentTimeMillis();
// do something
long end = System.currentTimeMillis() - start;
}
}

二、AOP代碼注入時機

代碼注入主要注解機制,根據注解時機的不同,主要分為運行時、加載時和編譯時。

運行時:你的代碼對增強代碼的需求很明確,比如,必須使用動態代理(這可以說并不是真正的代碼注入)。 加載時:當目標類被Dalvik或者ART加載的時候修改才會被執行。這是對Java字節碼文件或者Android的dex文件進行的注入操作。 編譯時:在打包發布程序之前,通過向編譯過程添加額外的步驟來修改被編譯的類。aspect切面編程正是運用到編譯時

三、AOP的幾種實現方式

  • Java 中的動態代理,運行時動態創建 Proxy 類實例
  • APT,注解處理器,編譯時生成 .java 代碼
  • Javassist for Android:一個移植到Android平臺的非常知名的操縱字節碼的java庫,對 class 字節碼進行修改
  • AspectJ:和Java語言無縫銜接的面向切面的編程的擴展工具(可用于Android)。

四,Android中使用 AspectJ

代表項目:Hugo(打印每個方法的執行時間) sa-sdk-android(全埋點技術)

(1)原理

AspectJ 意思就是Java的Aspect,Java的AOP。它的核心是ajc(編譯器 aspectjtools)和 weaver(織入器 aspectjweaver)。

ajc編譯器:基于Java編譯器之上的,它是用來編譯.aj文件,aspectj在Java編譯器的基礎上增加了一些它自己的關鍵字和方法。因此,ajc也可以編譯Java代碼。

weaver織入器:為了在java編譯器上使用AspectJ而不依賴于Ajc編譯器,aspectJ 5出現了 @AspectJ,使用注釋的方式編寫AspectJ代碼,可以在任何Java編譯器上使用。 由于AndroidStudio默認是沒有ajc編譯器的,所以在Android中使用@AspectJ來編寫。它在代碼的編譯期間掃描目標程序,根據切點(PointCut)匹配,將開發者編寫的Aspect程序編織(Weave)到目標程序的.class文件中,對目標程序作了重構(重構單位是JoinPoint),目的就是建立目標程序與Aspect程序的連接(獲得執行的對象、方法、參數等上下文信息),從而達到AOP的目的。

(2)AspectJ 術語

切面(Aspect):一個關注點的模塊化,這個關注點實現可能另外橫切多個對象。其實就是共有功能的實現。如日志切面、權限切面、事務切面等。

通知(Advice):是切面的具體實現。以目標方法為參照點,根據放置的地方不同,可分為

  1. 前置通知(Before)、
  2. 后置通知(AfterReturning)、
  3. 異常通知(AfterThrowing)、
  4. 最終通知(After)
  5. 環繞通知(Around)5種。

在實際應用中通常是切面類中的一個方法,具體屬于哪類通知由配置指定的。

切入點(Pointcut):用于定義通知應該切入到哪些連接點上。不同的通知通常需要切入到不同的連接點上,這種精準的匹配是由切入點的正則表達式來定義的。 連接點(JoinPoint):就是程序在運行過程中能夠插入切面的地點。例如,方法調用、異常拋出或字段修改等。

目標對象(Target Object):包含連接點的對象,也被稱作被通知或被代理對象。這些對象中已經只剩下干干凈凈的核心業務邏輯代碼了,所有的共有功能等代碼則是等待AOP容器的切入。

AOP代理(AOP Proxy):將通知應用到目標對象之后被動態創建的對象。可以簡單地理解為,代理對象的功能等于目標對象的核心業務邏輯功能加上共有功能。代理對象對于使用者而言是透明的,是程序運行過程中的產物。

編織(Weaving):將切面應用到目標對象從而創建一個新的代理對象的過程。這個過程可以發生在編譯期、類裝載期及運行期,當然不同的發生點有著不同的前提條件。譬如發生在編譯期的話,就要求有一個支持這種AOP實現的特殊編譯器(如AspectJ編譯器);

發生在類裝載期,就要求有一個支持AOP實現的特殊類裝載器;只有發生在運行期,則可直接通過Java語言的反射機制與動態代理機制來動態實現(如搖一搖)。

**引入(Introduction):**添加方法或字段到被通知的類。

(3)在Android項目中使用AspectJ

  • gradle配置的方式:引入AspectJ是有點復雜的,需要引入大量的gradle命令配置有點麻煩,在build文件中添加了一些腳本,文章出處:https://fernandocejas.com/2014/08/03/aspect-oriented-programming-in-android/
  • 使用 gradle 插件(也是對 gradle 命令進行了包裝):Jake Wharton 大神的 hugo 項目(一款日志打印的插件)

上海滬江團隊的 gradle_plugin_android_aspectjx 一個基于AspectJ并在此基礎上擴展出來可應用于Android開發平臺的AOP框架,可作用于java源碼,class文件及jar包,同時支持kotlin的應用。

AOP的用處非常廣,從spring到Android,各個地方都有使用,特別是在后端,Spring中已經使用的非常方便了,而且功能非常強大,但是在Android中,AspectJ的實現是略閹割的版本,并不是所有功能都支持,但對于一般的客戶端開發來說,已經完全足夠用了。

(4)以 AspectJX 接入說明

  • 首先,需要在項目根目錄的build.gradle中增加依賴:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
}
}
  • 然后module項目的 build.gradle 中加入 AspectJ 的依賴:
apply plugin: 'android-aspectjx'
dependencies {
compile 'org.aspectj:aspectjrt:1.8.+'
}
aspectjx {
//排除所有package路徑中包含`android.support`的class文件及庫(jar文件)
exclude 'org.apache.httpcomponents'
exclude 'android.support'
}
  • 具體配置參見github地址 https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx
  • 我們通過一段簡單的代碼來了解下基本的使用方法和功能,新建一個AspectTest類文件,代碼如下:
@Aspect
public class AspectTest {
private static final String TAG = "xuyisheng";
@Before("execution(* android.app.Activity.on**(..))")
public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable {
String key = joinPoint.getSignature().toString();
Log.e(TAG, "onActivityMethodBefore: " + key);
}
@After("execution(* android.app.Activity.on**(..))")
public void onActivityMethodAfter(JoinPoint joinPoint) throws Throwable {
String key = joinPoint.getSignature().toString();
Log.e(TAG, "onActivityMethodAfter: " + key);
}
@Around("execution(* android.app.Activity.on**(..))")
public void onActivityMethodAfter(ProceedingJoinPoint joinPoint) throws Throwable {
String key = joinPoint.getSignature().toString();
Log.e(TAG, "onActivityMethodBefore: " + key);
joinPoint.proceed();
Log.e(TAG, "onActivityMethodAfter: " + key);
}
}

在類的最開始,我們使用 @Aspect 注解來定義這樣一個AspectJ文件,編譯器在編譯的時候,就會自動去解析,并不需要主動去調用AspectJ類里面的代碼。

(5)編織速度優化建議

  • 盡量使用精確的匹配規則,降低匹配時間。
  • 排除不需要掃描的包。

通過這種方式編譯后,我們來看下生成的代碼是怎樣的。AspectJ的原理實際上是在編譯的時候,根據一定的規則解析,然后插入一些代碼,通過aspectj生成的代碼,會在Build目錄下:

AOP與OOP有什么區別,談談AOP的原理是什么

四、總結:

Aspectj:

  • AspectJ除了hook之外,AspectJ還可以為目標類添加變量,接口。另外,AspectJ也有抽象,繼承等各種更高級的玩法。它能夠在編譯期間直接修改源代碼生成class。
  • AspectJ語法比較多,但是掌握幾個簡單常用的,就能實現絕大多數切片,完全兼容Java(純Java語言開發,然后使用AspectJ注解,簡稱@AspectJ。)

我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(0)
領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

阿拉斯加垂钓APP下载
辽宁十一选五 亿鑫配资 金证通配资 初赔与即时赔率的意义 陕西快乐十分 湖南快乐10分 股票推荐网站在线支付 天赐配资 富深所配资 指南针股票分析软件手机版 股融贷配资 壹点顺配资 雷速体育比分直播电脑版 重庆快乐10分 股票配资平台 趣操盘