AOP

Guice提供了MethodInterceptor的功能,讓你可以做Method的前置處理。有以下幾個步驟:

  1. 需要aopalliance.jar。
  2. 建立對應處理的Annotation。
  3. 建立處理的Interceptor。
  4. 透過Module將Annotation與Interceptor做連結,並指定作用類別。
  5. 透過Injector取得提供服務的Instance。

我們以刷卡服務做為範例,在扣款前我們會先確認信用卡內容是否正確。以往我們會把檢查動作寫在charge的method最前面,但透過AOP可以讓我們把這動作變得可以重複使用。在這我宣告了ValidCreditCard的Annotation做註記。

public class BillingService implements IBillingService {
	@Override
	@ValidCreditCard
	public IChargeResult charge(String amount, CreditCard creditCard) {
		
		return null;
	}
}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
public @interface ValidCreditCard {

}
接著實做MethodInterceptor介面的類別CreditCardInterceptor,用以確認信用卡資料是否正確。主要重點是,我們可以透過MethodInvocation參數去得被呼叫method的參數,然後再去做我們想做的事情。
public class CreditCardInterceptor implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation arg0) throws Throwable {
		CreditCard creditCard = getCreditCardArgument(arg0.getArguments());
		verify(creditCard);
		return arg0.proceed();
	}

        ...
}
接著實做Module類別,以做Annotation與對應Interceptor綁定。bindInterceptor第一個參數可以設定你希望有此功能的類別有哪些,第二個參數則是對應Annotation,第三個參數是處理的Interceptor。
public class BillingModule extends AbstractModule {
	@Override
	protected void configure() {
		bindInterceptor(Matchers.any(),
				Matchers.annotatedWith(ValidCreditCard.class), 
				new CreditCardInterceptor());
	}
}
測試程式可以這樣寫:
public class BillingClient {
	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new BillingModule());
		BillingService billingService = injector.getInstance(BillingService.class);
		billingService.charge("1000", new CreditCard("1234-5678-6666-0001-5555"));
		try {
			billingService.charge("1000", new CreditCard("1234-5678-6666-0001"));
		} catch( Throwable e ){
			e.printStackTrace();
		}
	}
}

友藏內心獨白: 第一次嘗試AOP寫法。