guice インターセプト 2008/01/06 に書いたもの

実際の開発で使ってみた Google guice インターセプタの定義は、
com.google.inject.Module を実装するクラスを用意して
configure(com.google.inject.Binder)メソッド
bindInterceptorメソッドによりマッチング条件でインターセプト
バインド定義するわけだが、任意のアノテーションアノテーション
マッチ条件とする場合、以下のようなstatic メソッドを用意する。

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import com.google.inject.matcher.AbstractMatcher;
import com.google.inject.matcher.Matcher;
import com.google.inject.util.Objects;
/**
 * インターセプトMatcher .
 * @Intercept アノテーションで指定する value 値と指定文字列が一致する時
 * にインターセプトする。
 * 例)ALogic の中のメソッドに、@Intercept("aaa") を付けた
 * メソッドを、ALogicIntercepter というインターセプタを実行したい場合は、
 * 以下のようにする。
 * binder.bindInterceptor(Matchers.inPackage(ALogic.class.getPackage())
 *                      ,InterceptMatcher.annotatedWith(Intercept.class,"aaa")
 *                      ,new ALogicIntercepter());
 * InterceptMatcher.annotatedWith(Intercept.class,string) stringは、重複不可!
 */
public final class InterceptMatcher {
    
   private InterceptMatcher(){}
   
   /**
    * @Intercept アノテーションで指定する value 値と指定文字列が一致する時に
    * インターセプトする。
    * @param annotationType
    * @param reqStr 指定文字列 JVM内でユニークなKey
    * @return Matcher<AnnotatedElement>
    */
   public static Matcher<AnnotatedElement> 
   annotatedWith(final Class<? extends Annotation> annotationType
                ,final String reqStr){
      Objects.nonNull(annotationType,"annotation type");
      return new AbstractMatcher<AnnotatedElement>(){
         public boolean matches(AnnotatedElement element) {
            Annotation annotation = element.getAnnotation(annotationType);
            if (annotation==null){
               return false;
            }
            return ((Intercept)annotation).value().equals(reqStr);
         }
         @Override
         public String toString() {
            return "annotatedWith("+annotationType.getSimpleName()
                                  +".class,"+reqStr+")";
         }
      };
   }
}
// インターセプトさせるメソッドアノテーション
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Intercept{
   String value();
}

// ALogicインターフェースと実装
public interface ALogic{
   public void action();
}
public class ALogicImpl implements ALogic{
   /*
    * ALogic#action()に、@Intercept を付与する。
    */
   @Intercept("aaa")
   public void action(){
      System.out.println("■ ALogic#action()");
   }
}
// バインド定義
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.matcher.Matchers;
import com.google.inject.name.Names;

public class AbcModule implements Module{
   public void configure(Binder binder){
      binder.bind(ALogic.class).annotatedWith(Names.named("alogic"))
      .to(ALogicImpl.class);
      // インターセプター  
      // InterceptMatcher.annotatedWith(Intercept.class,string)
      // の stringは、重複セット不可!
      // @Intercept("aaa") が、ALogicIntercepter によりインターセプトされる
      // ことを約束させる
      binder.bindInterceptor(Matchers.inPackage(ALogic.class.getPackage())
                            ,InterceptMatcher.annotatedWith(Intercept.class,"aaa")
                            ,new ALogicIntercepter());
   }
}
//======= インターセプターの準備
/*
 * インターセプター抽象クラス
 */
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public abstract class AbstarctIntercepter  implements MethodInterceptor{
   /**
    * 前処理
    */
   public abstract void preProcess();
   
   /**
    * 後処理
    */
   public abstract void afterProcess();
   
   /* インターセプト
    * @see org.aopalliance.intercept.MethodInterceptor#invoke(
    *         org.aopalliance.intercept.MethodInvocation)
    */
   public Object invoke(MethodInvocation m) throws Throwable{
      try{
      // 前処理実行
      this.preProcess();
      // 処理実行
      Object obj = m.proceed();
      // 後処理実行
      this.afterProcess();
      return obj;
      }catch(Exception e){
         throw e;
      }finally{
      }
   }
}
// AbstarctIntercepter の具象クラス→ ALogicIntercepter
public class ALogicIntercepter extends AbstarctIntercepter{
   @Override
   public void afterProcess(){
      System.out.println("■ ALogicIntercepter#afterProcess()");
   }
   @Override
   public void preProcess(){
      System.out.println("■ ALogicIntercepter#preProcess()");
   }
}
//======= 実行するDIクラス
import com.google.inject.Inject;
import com.google.inject.name.Named;
public class AClient{
   // ALogic は、ALogicImplで生成される。
   @Inject @Named("alogic") private ALogic alogic;
   
   public void execA(){
      this.alogic.action();
   }
}
//====== DIを実施して実行する。
import com.google.inject.Guice;
import com.google.inject.Injector;
        :
    :
   Injector injector = Guice.createInjector(new AbcModule());
   AClient client = injector.getInstance(AClient.class);
   client.exeA();