MyBatis源码解读(2)——MapperProxy

SqlSession可以说凡是整整MyBatis的严重性,在SqlSession中提到到前一篇四大对象:Executor、StatementHandler、ParameterHandler、ResultHandler,所以于斯先只针对SqlSession有一个横的询问。

每当代码中我们得以看来当我们组织出一个SqlSession实例过后,可以经过SqlSession构造出Mappper映射器。UserMapper是一个接口,那么我们可以得的凡,它肯定是故了Java的动态代理生成了一个代理类。

SqlSession sqlSession = SessionFactory.getSqlSession(resource); 
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

就上同一篇讲话到通过DefaultSqlSessionFactory可以博得一个SqlSession的实例DefaultSqlSession。

图片 1

经过源代码可以窥见,SqlSessionManger又实现了SqlSession,在高达亦然省中但是清楚SqlSessionManager同样也继承了SqlSessionFactory接口。我们拿它构成起来看。

图片 2

 

总的看这个SqlSessionManager有点神奇,同时继续SqlSession和SqlSessionFactory。从名字上来拘禁好像是管理SqlSession的,这里不讨论,随着源代码的开卷相信我们会浸清晰,包括所有保险的构造。

回来DefaultSqlSession中来。在SqlSession接口中提供了好多智,用于我们的增删改查,这当旧版的MyBatis或者iBatis中时所使用的,我们现大多直接运用xml配置文件为达成更加灵活的职能。所以我们以注意力放在getMapper方法上。

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

小心UserMapper仅仅是一个接口,这里见面提到到Java的动态代理,所以得要发生自然之功底才能够诵懂。

经过打断点调试我们得发现真正有了一个深受MapperProxy的代理类。

图片 3

下面是DefaultSqlSession的getMapper方法:

//org.apache.ibatis.session.default.DefaultSqlSession
public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
}

圈起语法有点意外,这是一个泛型方法。看来是调用了Configuration的getMapper方法,还无是DefaultSqlSession实现了getMapper。接着再拘留Configuration的getMapper方法:

//org.apache.ibatis.session.Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}

 Configuration.getMapper一共两只参数,一个是Class类型,一个凡是SqlSession,在DefaultSqlSession.getMapper调用Configuration.getMapper时,将传递进入的Class类型参数和夫自我传递让了Configuration.getMapper。此时还免是于Configuration中落实了getMapper,看来要一个名叫mapperRegistry的变量。

//org.apache.ibatis.session.Configuration
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);

圈在名字好像是注册Mapper映射器的地方,想来也是,既然要落Mapper的照,那么富有的Mapper都如一个地方去报(在我们的mybytis-config.xml里),注册好之后需之当儿更错过探寻是否都注册,那么就是MapperRegistry,所以博得一个好之变量名是异常主要的。

 1 //org.apache.ibatis.binding.MapperRegistry
 2 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
 3   final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
 4   if (mapperProxyFactory == null) {
 5     throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
 6   }
 7   try {
 8     return mapperProxyFactory.newInstance(sqlSession);
 9   } catch (Exception e) {
10     throw new BindingException("Error getting mapper instance. Cause: " + e, e);
11   }
12 }

每当第3实施代码中试图从一个深受knownMappers的变量取出MapperProxyFactory。这个knownMapper的概念:

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

既能够就此get方法取得,那说明就是发出add方法了?果不其然我们在MapperRegistry类中窥见了public
<T> void addMapper(Class<T>
type)方法,那么是于何调用的这个点子为?

我们来还理一调理。

采用MyBatis的首先步是布局mybatis-config.xml,配置好下,mybatis-config跑起的第一步也得是率先解析xml配置文件,将分析好之安排文件相继配置参数放入Configuration对象吃,包括Mapper的配置,所以理应是以解析xml文件的某部类中剖析过来后调整用Configuration的法门以mapper放置到MapperRegister中。事实为的确如此,有趣味可以跟踪下代码看看。回到MapperRegistry.getMapper的措施吃。

当我们所有对时,我们就会获取到一个MapperProxyFactory实例。想必MapperProxy代理类的变正是经过MapperProxyFactory工厂类构建的,即第8实行代码。进入MapperProxyFactory类。

//org.apache.ibatis.binding.MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
}

以这边终于盼了MapperProxy代理类,是经过sqlSession、mapperInterface、mechodCache三个参数构造的。

newInstance有一个重载方法:

//org.apache.ibatis.binding.MapperProxyFactory
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

算是是活动到头了,这里虽是归的一个代理类实例。最后来看看MapperProxy。

MapperProxy是一个关键之类似,所以我们以那个代码全部粘起:

 1 //org.apache.ibatis.binding.MapperProxy
 2 public class MapperProxy<T> implements InvocationHandler, Serializable {
 3 
 4   private static final long serialVersionUID = -6424540398559729838L;
 5   private final SqlSession sqlSession;
 6   private final Class<T> mapperInterface;
 7   private final Map<Method, MapperMethod> methodCache;
 8 
 9   public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
10     this.sqlSession = sqlSession;
11     this.mapperInterface = mapperInterface;
12     this.methodCache = methodCache;
13   }
14 
15   @Override
16   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
17     if (Object.class.equals(method.getDeclaringClass())) {
18       try {
19         return method.invoke(this, args);
20       } catch (Throwable t) {
21         throw ExceptionUtil.unwrapThrowable(t);
22       }
23     }
24     final MapperMethod mapperMethod = cachedMapperMethod(method);
25     return mapperMethod.execute(sqlSession, args);
26   }
27 
28   private MapperMethod cachedMapperMethod(Method method) {
29     MapperMethod mapperMethod = methodCache.get(method);
30     if (mapperMethod == null) {
31       mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
32       methodCache.put(method, mapperMethod);
33     }
34     return mapperMethod;
35   }
36 
37 }

假定采取Java的动态代理就务须得落实InvocationHandler接口,在第17履代码中首先判断代理对象是一个接口还是一个好像,显然我们从没针对性mapper接口进行其它实现,那么其以格外成一个MapperMethod对象,接着调用其execute方法,把sqlSession和参数传递进去。

 

网站地图xml地图