一、前言
在上一篇《Mybatis源码学习(15)-binding模块之MapperMethod类》中,已经概述了Mybatis中binding模块的相关概念,同时详细分析了MapperMethod类。这一篇我们来分析binding模块中剩余的类,分别是MapperProxyFactory、MapperProxy、MapperRegistry等。
二、MapperProxy类
MapperProxy类是InvocationHandler接口的实现,用来在面向接口编程过程中,根据接口、对应的XML文件产生的一个代理实现的代理对象。
- 字段、构造函数
在MapperProxy类中,有三个关键属性字段,其中,sqlSession用来记录关联的SqlSession对象,其实再生成的代理对象实例中,真正操作数据库SQL语句的时候,还是由SqlSession对象完成的;mapperInterface字段对应了该代理对象对应的Mapper接口;methodCache字段用来缓存MapperMethod对象,MapperMethod对象定义了Mapper接口中对应方法的信息以及对应SQL语句的信息,用来完成参数转换以及SQL语句的执行功能。构造函数主要是用来初始化实例对象,同时为这三个字段赋值。
//记录关联的SqlSession对象
private final SqlSession sqlSession;
//记录Mapper接口对应的Class对象
private final Class<T> mapperInterface;
//用于缓存MapperMethod对象,其中key是Mapper接口中方法对应的Method对象, value是对应的MapperMethod对象。
//MapperMethod对象会完成参数转换以及SQL语句的执行功能
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;
}
- invoke()方法
动态代理对象的核心处理逻辑,首先通过cachedMapperMethod()方法获取方法对应的MapperMethod对象,获取过程中如果没有在缓存中,就加入到缓存中,然后根据MapperMethod对象在进行真正的数据库的相关操作,即在MapperMethod.execute()方法中真正实现数据库操作逻辑。MapperMethod.execute()方法的具体实现在上一篇已经分析,这里不再重复。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {//如果目标方法继承自Object,则直接调用目标方法
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {//针对Java7以上版本对动态类型语言的支持,不进行详述
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
三、MapperProxyFactory类
MapperProxyFactory类主要用来创建代理对象,比较简单,代码如下所示:
public class MapperProxyFactory<T> {
//当前MapperProxyFactory对象可以创建实现了mapperInterface接口的代理对象
private final Class<T> mapperInterface;
//缓存, key是mapperinterface接口中某方法对应的Method对象, value是对应的MapperMethod对象
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
/**
* 创建实现了mapperinterface接口的代理对象
* @param mapperProxy
* @return
*/
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
/**
* 创建MapperProxy对象,每次调用都会创建新的MapperProxy对象
* @param sqlSession
* @return
*/
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
三、MapperRegistry类
MapperRegistry类是Mapper接口及其对应的代理对象工厂的注册中心。
- 字段、构造函数
其中,Configuration对象, MyBatis全局唯一的配置对象,其中包含了所有配置信息;knownMappers 记录了Mapper接口与对应MapperProxyFactory之间的关系。构造函数还是用来实例化对象和字段赋值。
//Configuration对象, MyBatis全局唯一的配置对象,其中包含了所有配置信息
private final Configuration config;
//记录了Mapper接口与对应MapperProxyFactory之间的关系
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
public MapperRegistry(Configuration config) {
this.config = config;
}
- getMapper()方法
根据对应的类获取对应的代理对象。供Configuration对象中的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);
}
}
- addMapper()方法
相关方法主要用来在加载和解析配置文件的时候,初始化knownMappers字段。后期执行SQL方法的时候,再根据对应的类进行创建对应的代理对象。
/**
* 在MyBatis初始化过程中会读取映射配置文件以及Mapper接口中的注解信息,
* 并调用MapperRegisty.addMapper()方法填充M叩perRegistry.knownMappers集合,
* 该集合的key是Mapper接口对应的Class对象, value为MapperProxyFactory工厂对象。
*
* @param type
*/
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {//验证要添加的映射器的类型是否是接口
if (hasMapper(type)) {//验证注册器集合中是否已存在该注册器(即重复注册验证),如果已存在则抛出绑定异常
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
//定义一个boolean值,默认为false,标识是否加载完成
boolean loadCompleted = false;
try {
//将Mapper接口对应的Class对象和MapperProxyFactory对象添加到knownMappers集合
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
//对使用注解方式的实现进行注册(一般不使用)
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
//设置loadCompleted的值为true,表示注册完成
loadCompleted = true;
} finally {
if (!loadCompleted) {//对注册失败的类型进行清除
knownMappers.remove(type);
}
}
}
}
/**
* 将包下满足以superType为超类的Mapper接口及其对应的代理对象工厂注册到注册中心中
* @since 3.2.2
*/
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
addMapper(mapperClass);
}
}
/**
* 用于仅指定包名的情况下,扫描包下的每个映射器进行注册
* @since 3.2.2
*/
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68896.html