SqlSession CLOSE忘れを回避するには、、(2)

SqlSession のCLOSE 忘れを回避する(1)の続きです。

クエリ用は、メソッド・インターセプタがトランザクションメソッドと区別
できるように、別のアノテーションを用意する

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * クエリー実行のみを約束する.
 * IBatisDao を継承してメソッドに@QueryLimited を付与する
 *
 * SqlSession を使う場合は、IBatisDao の getSqlSession() を使う。
 * 任意のSQLMapper インスタンスを取得する場合は、IBatisDao の
 * public <T> T getMapper(Class<T> t) を使う。T は、interface
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface QueryLimited{
}

つまり、コミットが必要なメソッドには、前回記述した@Transaction を、
クエリしか実行しないメソッドには、@QueryLimited を付ける。

クエリー実行限定 インターセプターは、以下のとおりでコミット
ロールバックは存在しない
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.google.inject.Inject;
/**
 * クエリー実行限定 インターセプター
 */

final class QueryLimitedExecutor implements MethodInterceptor{
   private SqlSessionFactory sqlSessionFactory;
   @Inject
   public QueryLimitedExecutor(SqlSessionFactory sqlSessionFactory){
      this.sqlSessionFactory = sqlSessionFactory;
   }
   @Override
   public Object invoke(MethodInvocation m) throws Throwable{

      Object rtn = null;
      SqlSession session = null;
      try{
      session = this.sqlSessionFactory.openSession(false);
      Field setField = this.getAnotatedField(ControleSession.class
,m.getMethod().getDeclaringClass());
      setField.setAccessible(true);
      setField.set(m.getThis(),session);
      rtn = m.proceed();
      }catch(Exception e){
         throw e;
      }finally{
         if (session != null) session.close();
      }
      return rtn;
   }
   private Field getAnotatedField(Class<? extends Annotation> a,Class<?> cls){
      Field rtn=null;
      Class<?> tcls = cls;
      while(!tcls.equals(java.lang.Object.class)){
         Field fls = tcls.getDeclaredFields();
         for(int i=0;i < fls.length;i++){
            Annotation
 as = fls[i].getAnnotations();
            if (as != null){
               for(int k=0;k < as.length;k++){
                  if (as[k].annotationType().equals(a)){
                     rtn = fls[i];
                     i = fls.length;
                     break;
                  }
               }
            }
         }
         if (rtn != null) return rtn;
         tcls = tcls.getSuperclass();
      }
      throw new RuntimeException("must be IBatisDao extends");
   }
}

Google guice に渡すバインド定義は、以下のようになる

@Transaciton に対して、TransactionExecutor
@QueryLimited に対して、QueryLimitedExecutor
がインタセプトされるようにする。
SqlSessionFactory は、インタセプタでも以外でもインジェクトされるように記述する


import java.io.IOException;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.matcher.Matchers;
/**
 * SqlSessionFactory または、トランザクション インターセプタをバインド.
 * コンストラクタで、configuration のXMLファイル名を指定する。
 * 引数なしコンストラクタを使用した場合は、
 * Configuration.xml が指定されたものとして解釈される。
 */

public class IBatisModule extends AbstractModule{
   final String configXmlName;
   /**
    * @param configXmlName configurationファイル名
    */

   public IBatisModule(){
      this.configXmlName = "Configuration.xml";
   }
   /**
    * @param configXmlName configurationファイル名
    */

   public IBatisModule(String configXmlName){
      this.configXmlName = configXmlName;
   }
   /*
    * @see com.google.inject.AbstractModule#configure()
    */

   @Override
   protected void configure(){
      Injector injector = Guice.createInjector(new AbstractModule(){
            @Override
            protected void configure(){
            }
            @SuppressWarnings("unused")
            @Provides
            protected SqlSessionFactory providedBatchSqlSession() throws IOException{
               return new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsReader(IBatisModule.this.configXmlName));
            }
         }
      );
      binder().bindInterceptor(Matchers.any(),Matchers.annotatedWith(Transaction.class)
                              ,injector.getInstance(TransactionExecutor.class));
      binder().bindInterceptor(Matchers.any(),Matchers.annotatedWith(QueryLimited.class)
                              ,injector.getInstance(QueryLimitedExecutor.class));

   }
}