MyBatis接口编程原理

解析下面这两行代码,暂且不考虑和spring结合:

// 通过sqlSession执行SQL语句
IMessage imessage = sqlSession.getMapper(IMessage.class);
messageList = imessage.queryMessageList(parameter);
第一步:为接口产生一个代理类

sqlSession 实现类 DefaultSqlSession

    public  T getMapper(Class type, SqlSession sqlSession) {
    MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}

那么knownMappers又是在哪初始化的呢?

//加载xml配置文件的时候会调用这个方法
public  void addMapper(Class type) {
    ...省略...
        try {
           //关键put方法
            this.knownMappers.put(type, new MapperProxyFactory(type));
            MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
            parser.parse();
            loadCompleted = true;
        } finally {
            if (!loadCompleted) {
                this.knownMappers.remove(type);
            }

        }
    }

}

MapperProxyFactory.java的源码
上面getMapper方法里面调用的 mapperProxyFactory.newInstance(sqlSession);
实际上就是生成一个接口的动态代理类

public class MapperProxyFactory {
private final Class mapperInterface;
private Map methodCache = new ConcurrentHashMap();

public MapperProxyFactory(Class mapperInterface) {
    this.mapperInterface = mapperInterface;
}
...省略...
 protected T newInstance(MapperProxy mapperProxy) {
    return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

public T newInstance(SqlSession sqlSession) {
    MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
    return this.newInstance(mapperProxy);
}
}
第二步:调用代理方法

执行接口的代理类的方法 == invokeHandler的invoke方法
这似乎动态代理的知识

 public class MapperProxy implements InvocationHandler
//估计加载配置的时候,把这个类初始化好
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//因为传进去的是接口,不是object,实体类的父类应该是object,不会执行
if (Object.class.equals(method.getDeclaringClass())) {
  try {
    return method.invoke(this, args);
  } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
  }
}
//这个是主要方法
final MapperMethod mapperMethod = cachedMapperMethod(method);
//信息查找完毕,开始执行
return mapperMethod.execute(sqlSession, args);
  }
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;
  }

下面看看初始化MapperMethod的代码

   public MapperMethod(Class mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, method);

}

初始化了一个SqlCommond

public static class SqlCommand {

//这两个属性至关重要,后面执行,要用到这两个属性
private final String name;
private final SqlCommandType type;

public SqlCommand(Configuration configuration, Class mapperInterface, Method method) throws BindingException {
 //把拼接好的namespace.id 拿到配置文件里面去查找
  String statementName = mapperInterface.getName() + "." + method.getName();
  MappedStatement ms = null;
  if (configuration.hasStatement(statementName)) {
    //查询结果放在MappedStatement  这个类很关键
    ms = configuration.getMappedStatement(statementName);
  } else if  ...省略...
  name = ms.getId();
  type = ms.getSqlCommandType();
  ...省略...

既然都查到关键信息
name == namespace.id)
SqlCommandType == 执行类型
下一步就开始执行呗

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
...省略...
(SqlCommandType.SELECT == command.getType()) {
  if (method.returnsVoid() && method.hasResultHandler()) {
    executeWithResultHandler(sqlSession, args);
    result = null;
  } else if (method.returnsMany()) {//返回值类型
    result = executeForMany(sqlSession, args);
  } else if (method.returnsMap()) {
    result = executeForMap(sqlSession, args);
  } else {
    Object param = method.convertArgsToSqlCommandParam(args);
    result = sqlSession.selectOne(command.getName(), param);
  }

你可能感兴趣的:(MyBatis接口编程原理)