mybatis 提供了两种配置方式
1、xml配置,SqlSession可直接调用
2、注解配置
1)可以直接调用接口方法。探求下执行的原理
org.apache.ibatis.session.Configuration.getMapper(Class<T>, SqlSession)
-->> org.apache.ibatis.binding.MapperRegistry.getMapper(Class<T>, SqlSession)
-->> org.apache.ibatis.binding.MapperProxyFactory.newInstance(SqlSession)
可以看到mybatis对 对应的接口(interface)进行了代理,而实现类是org.apache.ibatis.binding.MapperProxy<T>(实现了java.lang.reflect.InvocationHandler接口)。
在该类中可以看到当我们调用接口的方法时,实际调用的是org.apache.ibatis.binding.MapperMethod的org.apache.ibatis.binding.MapperMethod.execute(SqlSession, Object[])方法,该方法里面实际调用的是SqlSession的相关方法。
在该方法中可以看到我们对传入的参数进行了封装org.apache.ibatis.binding.MapperMethod.ParamMap<Object>(继承java.util.HashMap<String, V>)。
我们在接口方法中可以使用org.apache.ibatis.annotations.Param注解参数,value()值就是封装后的map中的key。
Configure对象:封装好的Myabtis的配置对象,程序一启动就加载完成
源码:
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;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {//是继承子Object的方法,则调用对象的原方法
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//否则调用自定义业务逻辑
//创建一个MapperMethod,mybatis的调用的封装
final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } private MapperMethod cachedMapperMethod(Method method) {
//先从方法缓存中取 //存储对象Key:接口的方法对象,Value:对应的MapperMethod 对象
MapperMethod mapperMethod = methodCache.get(method); if (mapperMethod == null) {//如果没有,则实例化一个 mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); methodCache.put(method, mapperMethod);//缓存对象,提高效率,下一次如果还访问的是同一个方法,则直接调用 } return mapperMethod; } }
MapperMethod对象封装了对应SqlSession的调用方法,通过key(接口对象+方法名称)去Configure中对应的MappedStatement(封装好的Myabtis的配置对象)。 参照源码,在execute方法中封装了SqlSession的调用。3、总结
不管是xml配置,还是注解配置,在程序启动后都会装配为MappedStatement,当调用时本质都是调用的SqlSession的方法。
1) Spring与Mybaits结合时,我们调用接口对象时,实际调用的是依旧是MapperMethod对象的execute方法。
Spring中接口的实例对象是Spring分配给我们的,怎么做的呢?
看mybatis-spring-1.2.2.jar包中的org.mybatis.spring.mapper.MapperFactoryBean对象,
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T>{
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}}
接口对象的代理实体就是getObject方法返回的对象