AOP不是一種語言,而是一種軟件工程方法。 像任何方法一樣,它具有不同的實現,并且AspectJ當前是最豐富,最完整的。 由于AspectJ和AspectWerkz合并,現在可以使用注釋創建方面。
開發人員編寫代碼的原因是為了提供某種功能。 對于這種討論,功能性的種類并不重要:有些人可能想提供業務功能,另一些人可能出于研究目的編寫代碼,而另一些人則純粹出于樂趣。 關鍵是任何信息系統都有其核心動機,即它想要提供的關鍵功能。 例如,我最近編寫了PODAM ,這是一個測試工具,其最終目標是自動填充POJO / JavaBean屬性。
每個信息系統也需要正交服務(AOP稱之為橫切關注點); 例如日志記錄,安全性,審核,異常管理等。 盡管信息系統可以分為不同的功能(AOP定義了連接點),但全面需要正交服務。 例如,如果要記錄每個公共方法執行所花的時間,則每個公共方法應具有以下偽代碼:
public void someBusinessMethod() {long start = System.currentTimeInMilliseconds();doTheBusinessFunctionality();long end = System.currentTimeInMilliseconds();log.debug("The execution of someBusinessMethod took " + (end - start) + " milliseconds");}
在上述方法中,核心功能僅由someBusinessMethod()標識,而其他所有功能僅是記錄活動。 最好有以下內容:
//Some external magic happens before the invocation of this method to take the start time
public void someBusinessMethod() {doTheBusinessFunctionality(); }
//Some external magic happens after the invocation of this method to take the end time and logs how long the execution took.
開發人員通常需要整個應用程序中的日志記錄,安全性等,而不是單一方法。 AOP允許開發人員通過在外部某個地方(稱為“方面”)定義行為以應用于匹配某種模式的所有代碼(AOP實際上允許更廣泛的功能集,例如添加接口,實例變量,方法,等等,只舉一個例子)。 然后,通過AOP所謂的Weaver,將這種授權的行為添加到最終執行代碼中。
可以通過多種方式實現:編織可以在源級別,二進制級別和加載時間進行。 您可以將編織器視為C和C ++中的鏈接器。 源和庫鏈接在一起以創建可執行文件; 編織者將Java代碼和方面結合在一起,以創建授權的行為。
Spring通過圍繞必須豐富其行為的代碼創建一個AOP代理來實現這種授權行為。 以下代碼顯示了一個基于AspectJ的非常簡單的示例; 該示例圍繞使用某些身份驗證服務執行簡單方法。
身份驗證服務看起來非常簡單(關鍵不是功能的實現方式,而是可用的身份驗證服務):
/*** */
package uk.co.jemos.aop;/*** A simple authenticator service.* * @author mtedone* */
public class Authenticator {public void authenticate() {System.out.println("Authenticated");}}Now let's have a look at the business logic:/*** */
package uk.co.jemos.aop;/*** A simple service which delivers messages* @author mtedone* */
public class MessageCommunicator {public void deliver(String message) {System.out.println(message);}public void deliver(String person, String message) {System.out.println(person + ", " + message);}}
我們希望在調用MessageCommunicator的任何業務方法之前先調用Authenticator。 使用AspectJ注釋語法,我們用純Java編寫Aspect:
package uk.co.jemos.aop;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class SecurityAspect { private Authenticator authenticator = new Authenticator();@Pointcut("execution(* uk.co.jemos.aop.MessageCommunicator.deliver(..))")public void secureAccess() {};@Before("secureAccess()")public void secure() {System.out.println("Checking and authenticating user...");authenticator.authenticate();}}
上面的代碼更加有趣。 一個方面用@Aspect注釋標記。 切入點是我們代碼中的一個關注點,我們希望我們的Aspect可以加入其中。語法
@Pointcut(“ execution(* uk.co.jemos.aop.MessageCommunicator.deliver(..))”)public void secureAccess(){};
意思是:“定義一個名為secureAccess的切入點,該切入點適用于MessageCommunicator類中的所有傳遞方法,而不管該方法的返回類型如何”。 接下來的內容被稱為建議,這是AOP增強班級行為的地方:
@Before("secureAccess()")
public void secure() {System.out.println("Checking and authenticating user...");authenticator.authenticate();}
上面的代碼說:“在對secureAccess()切入點進行任何匹配之前,將代碼應用到塊中”。 以上所有內容都是純Java,盡管注釋屬于AspectJ運行時。 為了在Spring中使用上述方面,我定義了一個Spring上下文文件:
<?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-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><aop:aspectj-autoproxy /><bean id="messageCommunicator" /><bean id="securityAspect" /></beans>
XML元素:<aop:aspectj-autoproxy />指示Spring圍繞各個方面創建代理。 現在,當我從客戶端使用MessageCommunicator時:
/**
* @param args
*/
public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:aop-appContext.xml");MessageCommunicator communicator = ctx.getBean("messageCommunicator",MessageCommunicator.class);communicator.deliver("Hello World");communicator.deliver("Marco", "Hello World");
}
我得到以下輸出:
信息:從類路徑資源[aop-appContext.xml]加載XML bean定義2011年5月15日11:51:41
org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO:在org.springframework.beans.factory.support.DefaultListableBeanFactory@21b64e6a中預先實例化單例:定義bean [org.springframework.aop.config.internalAutoProxyCreator,messageCommunicator,securityAspect]; 工廠層次結構的根檢查和認證用戶…認證的Hello World 正在檢查和認證用戶…已認證Marco,Hello World
通過允許我們將外部組件中的橫切關注點外部化,然后在需要時將其編織到我們的代碼中,AOP大大改變了我們思考軟件工程的方式,這允許編寫更簡潔,更可維護的代碼,并且實現不受限制。 另外,如果我們通過使它們可重用而謹慎地編寫我們的方面,我們可以快速地建立一個通用,可重用方面的庫,以注入的方式為我們的代碼添加功能。
采用AOP顯然存在弊端,主要是開發人員熟悉該技術所需的學習曲線。 如上面的示例所示,AspectJ定義了自己的語言和語法); @Before注釋只是一種可能性:建議可以在對象之前,之后,周圍使用; 此外,定義切入點的語法不是Java,而是類似腳本的語法。 AspectJ方面還具有關鍵字和本機對象,以捕獲他們建議的連接點的上下文,并且需要學習此語法。 但是,通過學習這項新穎而令人興奮的技術所需的額外努力,潛在的收益將大大增加。
參考: Marco Tedone博客中的 JCG合作伙伴 Marco Tedone 使用AspectJ和Spring簡化了AOP 。
翻譯自: https://www.javacodegeeks.com/2012/04/aop-made-easy-with-aspectj-and-spring.html