// Path: src/main/java/com/github/mybatis/util/ReflectionUtil.java
// public class ReflectionUtil {
//   private static final LoadingCache<String, Field> CACHE = buildCache();
// 
//   private static LoadingCache<String, Field> buildCache() {
//     return CacheBuilder.newBuilder().maximumSize(1000).build(new CacheLoader<String, Field>() {
//       @Override
//       public Field load(String key) throws Exception {
//         int pos = key.lastIndexOf('#');
//         String className = key.substring(0, pos);
//         String fieldName = key.substring(pos + 1);
//         Class clz = Class.forName(className);
//         Field field = getDeclaredField(clz, fieldName);
//         makeAccessible(field);
//         return field;
//       }
//     });
//   }
// 
//   /**
//    * 循环向上转型,获取对象的DeclaredField.
//    */
//   public static void makeAccessible(final Field field) {
//     if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
//       field.setAccessible(true);
//     }
//   }
// 
//   /**
//    * 循环向上转型,获取类对象的DeclaredField.
//    */
//   public static Field getDeclaredField(Class<?> clz, final String fieldName) {
//     for (Class<?> s = clz; s != Object.class; s = s.getSuperclass()) {
//       try {
//         return s.getDeclaredField(fieldName);
//       } catch (NoSuchFieldException ignored) {
//       }
//     }
//     return null;
//   }
// 
//   /**
//    * 获取类属性，无视private/protected限制，不经过getter方法
//    *
//    * @param object    类对象
//    * @param fieldName 属性名
//    * @param <T>       目标类型
//    * @return
//    */
//   @SuppressWarnings("unchecked")
//   public static <T> T getFieldValue(Object object, String fieldName) {
//     Field field = CACHE.getUnchecked(object.getClass().getName() + '#' + fieldName);
//     if (field == null) {
//       throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
//     }
// 
//     Object result = null;
//     try {
//       result = field.get(object);
//     } catch (IllegalAccessException ignored) {
//     }
//     return (T) result;
//   }
// }


import com.github.mybatis.util.ReflectionUtil;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;
package com.github.mybatis.interceptor;



/**
 * 读写分离插件
 *
 * Created by lirui on 15/1/7.
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class MasterSlaveInterceptor implements Interceptor {
  private static final ThreadLocal<Boolean> READ_ONLY_LOCAL = new ThreadLocal<Boolean>();

  public static boolean isReadOnly() {
    return Boolean.TRUE.equals(READ_ONLY_LOCAL.get());
  }

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
    MappedStatement mappedStatement;
    if (statementHandler instanceof RoutingStatementHandler) {
// Path: src/main/java/com/github/mybatis/util/ReflectionUtil.java
// public class ReflectionUtil {
//   private static final LoadingCache<String, Field> CACHE = buildCache();
// 
//   private static LoadingCache<String, Field> buildCache() {
//     return CacheBuilder.newBuilder().maximumSize(1000).build(new CacheLoader<String, Field>() {
//       @Override
//       public Field load(String key) throws Exception {
//         int pos = key.lastIndexOf('#');
//         String className = key.substring(0, pos);
//         String fieldName = key.substring(pos + 1);
//         Class clz = Class.forName(className);
//         Field field = getDeclaredField(clz, fieldName);
//         makeAccessible(field);
//         return field;
//       }
//     });
//   }
// 
//   /**
//    * 循环向上转型,获取对象的DeclaredField.
//    */
//   public static void makeAccessible(final Field field) {
//     if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
//       field.setAccessible(true);
//     }
//   }
// 
//   /**
//    * 循环向上转型,获取类对象的DeclaredField.
//    */
//   public static Field getDeclaredField(Class<?> clz, final String fieldName) {
//     for (Class<?> s = clz; s != Object.class; s = s.getSuperclass()) {
//       try {
//         return s.getDeclaredField(fieldName);
//       } catch (NoSuchFieldException ignored) {
//       }
//     }
//     return null;
//   }
// 
//   /**
//    * 获取类属性，无视private/protected限制，不经过getter方法
//    *
//    * @param object    类对象
//    * @param fieldName 属性名
//    * @param <T>       目标类型
//    * @return
//    */
//   @SuppressWarnings("unchecked")
//   public static <T> T getFieldValue(Object object, String fieldName) {
//     Field field = CACHE.getUnchecked(object.getClass().getName() + '#' + fieldName);
//     if (field == null) {
//       throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
//     }
// 
//     Object result = null;
//     try {
//       result = field.get(object);
//     } catch (IllegalAccessException ignored) {
//     }
//     return (T) result;
//   }
// }


// Path: src/main/java/com/github/mybatis/interceptor/MasterSlaveInterceptor.java
import com.github.mybatis.util.ReflectionUtil;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;

package com.github.mybatis.interceptor;



/**
 * 读写分离插件
 *
 * Created by lirui on 15/1/7.
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class MasterSlaveInterceptor implements Interceptor {
  private static final ThreadLocal<Boolean> READ_ONLY_LOCAL = new ThreadLocal<Boolean>();

  public static boolean isReadOnly() {
    return Boolean.TRUE.equals(READ_ONLY_LOCAL.get());
  }

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
    MappedStatement mappedStatement;
    if (statementHandler instanceof RoutingStatementHandler) {
      StatementHandler delegate = ReflectionUtil.getFieldValue(statementHandler, "delegate");