インターフェースを使用するには、原則としてMyBatisのマッパー
MyBatisの3マッパーインターフェイスは、SQLのXML設定を実行する方法をお勧めします、使いやすく、かつ非常に柔軟です。利便性の残りの部分では、私はまた、一般的に行うにはJDKのダイナミックプロキシによって知る前に、これを達成する方法を知っていただきたいと思いますが、今回は詳細を知りたいと思いました。
シンプルでとてもより複雑な多くのものは、コール・マッパーインタフェースの理解を開発するだけでMyBatisのCRUD 3.4.0を利用しています。
典型的には、XML構成ファイルで作成されSqlSessionFactory
たオブジェクト、および次いで得るSqlSession
オブジェクトを、その後、カスタムインターフェイスプロキシオブジェクトマッパー最後のメソッド呼び出しインターフェース、以下の例を得ました。
/**
*
* @author xi
* @date 2018/10/01 14:12
*/
public class Demo {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(1L);
System.out.println(role);
}
}
どのようにこのセッションを取得、工場を作成し、コンフィギュレーションファイルを解析焦点ではありませんし、次の行を直接見ることができます。
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
カスタム取得方法Mapperプロキシオブジェクトは、次の場所にありますorg.apache.ibatis.session.SqlSession#getMapper
、またはジェネリックメソッド
/**
* Retrieves a mapper.
* @param <T> the mapper type
* @param type Mapper interface class
* @return a mapper bound to this SqlSession
*/
<T> T getMapper(Class<T> type);
サブクラスは、このメソッドを実装している:DefaultSqlSession
とSqlSessionManager
、デフォルトの実装にどこ注意:org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
Configurationオブジェクトが登場し、オブジェクトは、単にそれがダウンしてフォローアップしていき、今同じ焦点ではありません、XML設定解析内容が含まれます:org.apache.ibatis.session.Configuration#getMapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
ここでは出現しMapperRegistry
、それが(Mapper.xmlの内容を解析し、オブジェクトをmapper
タグはnamespace
HashMapのメンバ変数を含む、インターフェイスマッパーの完全修飾名が含まれている)来るorg.apache.ibatis.binding.MapperRegistry#knownMappers
キーがマッパーインターフェースであり、Class
値は、オブジェクトorg.apache.ibatis.binding.MapperProxyFactory
、名前から分かるように後で使用されるプロキシオブジェクト工場マッパーインターフェイスを作成するために使用されます。
特に、これはknownMappers
、詳細として、埋めるためにどのようにorg.apache.ibatis.binding.MapperRegistry#addMapper
関係なく、ダウンして行くことが最初であることの、方法:org.apache.ibatis.binding.MapperRegistry#getMapper
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
型マッパーインターフェイスによってknownMappers
得る対応する植物、その後、フォローアップしていき、プロキシオブジェクトを作成します。org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
ここで再びそこにあるMapperProxy
ターゲット、プロキシオブジェクトは、それが実装開くことが理解されるべきでjava.lang.reflect.InvocationHandler
すごい売却しようとしているインタフェースを、。
フォローアップしていき、犬を見てはいけません。org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.binding.MapperProxy<T>)
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
この中で、私はお馴染みのを参照してくださいjava.lang.reflect.Proxy
ここでは、mapperInterface
工場出荷時のマッパー・インターフェースを作成するときに渡されます。実際のプロキシオブジェクトマッパーインターフェイスを生成するには、この時間は、本当に羊の頭です。
これは、犬の前であるため、それに精通しているどんな、両方馴染みとなじみのないJDKダイナミックプロキシーないmapperProxy
でInvocationHandler
プロキシ・オブジェクト・インターフェース・メソッドに対するすべての呼び出しをインターセプトオブジェクト。JDKダイナミックプロキシが前に、ここでは表示されませんでしたとき具象サブクラスの使用はインターフェイスを実装しますので、それは奇妙です。その後を見てみましょうorg.apache.ibatis.binding.MapperProxy
:
/**
* @author Clinton Begin
* @author Eduardo Macarron
*/
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断 method 是不是 Object 类的方法,如 hashCode()、toString()
if (Object.class.equals(method.getDeclaringClass())) {
try {// 如果是,则调用当前 MapperProxy 对象的这些方法
// 跟 Mapper 接口的代理对象没关系
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
// 到这了,说明调用的是接口中的方法,具体的执行就不是本次关注的重点了
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
// 对 MapperMethod 做了缓存,这个 methodCache 是个 ConcurrentHashMap,在 MapperProxyFactory 中创建的
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
具体的な手順は、コードのコメント内で何も言うことはありません。
概要
- JDKダイナミックプロキシモードでは、プロキシ・オブジェクト・マッパー・インターフェースを作成し、切片が方法をインタフェースする呼び出し、
- マッパーインターフェースは、特定の理由を参照して、頑丈で使用することができない
org.apache.ibatis.binding.MapperMethod.SqlCommand#SqlCommand
、それに依存してもよいですorg.apache.ibatis.session.Configuration#mappedStatements
。
最後に、最後の、良い古いことわざ:決定に失敗し、最初大きな龍を開きます(ソースコードを参照してください)(エスケープ