Mybatis 之 构造Mapper (MapperProxy)
来源:互联网 发布:北京sql培训 编辑:程序博客网 时间:2024/05/18 03:50
我们在代码中使用:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
查看DefaultSqlSession的getMapper方法:
@Override public <T> T getMapper(Class<T> type) { return configuration.<T>getMapper(type, this); }
接着再看Configuration的getMapper方法:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
看来还是一个MapperRegistry的对象在处理Mapper:
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的变量取出MapperProxyFactory。
我们看看这个knownMapper在MapperRegistry中的定义:
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
有getMapper方法,那么必然后addMapper方法:
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 loadCompleted = false; try { 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; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }
我们在回过头来看getMapper是如何获得Mapper对象的:
1.先获取MapperProxyFactory
2.再调用MapperProxyFactory对象的newInstance方法获得Mapper。
我们看MapperProxyFactory代码:
public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
这里就是返回的一个代理类实例MapperProxy。
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 { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, 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; } @UsesJava7 private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable { final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class .getDeclaredConstructor(Class.class, int.class); if (!constructor.isAccessible()) { constructor.setAccessible(true); } final Class<?> declaringClass = method.getDeclaringClass(); return constructor .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC) .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args); } /** * Backport of java.lang.reflect.Method#isDefault() */ private boolean isDefaultMethod(Method method) { return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC) && method.getDeclaringClass().isInterface(); }}
要使用Java的动态代理就必须得实现InvocationHandler接口:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); }
首先判断代理对象是一个接口还是一个类,显然我们没有对mapper接口进行任何实现,那么它将执行
final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);
生成一个MapperMethod对象,接着调用其execute方法,把sqlSession和参数传递进去,执行Mapper方法。
阅读全文
2 0
- Mybatis 之 构造Mapper (MapperProxy)
- Mybais之MapperProxy
- Springmvc+mybatis+easyui 构造方法和mapper
- MyBatis之Mapper动态代理
- Mybatis之mapper代理方法
- MyBatis之 mapper代理方式
- Mybatis之Mapper动态代理
- mybatis原理之mapper实现
- mybatis之mapper的配置
- Mybatis之mapper XML 文件
- Mybatis之Mapper动态代理
- mybatis日记之mapper参数判断
- MyBatis集合Spring(三)之mapper
- Mybatis-Dao层开发之Mapper接口
- Mybatis学习二之Mapper XML 文件
- Mybatis学习之Mapper工具实践
- Mybatis学习笔记之mapper代理
- Mybatis小结之详解Mapper.xml
- 数据结构上机实践第二周项目2- 程序的多文件组织
- 以太网帧格式
- 正则表达式 分组
- MySQL 存储引擎(MyISAM、InnoDB、NDBCluster)
- map 按key和value排序
- Mybatis 之 构造Mapper (MapperProxy)
- java代理模式详解(动态代理)
- 王爽 《汇编语言》 读书笔记 十一 标志寄存器
- 游戏手柄(JoyStick)编程学习笔记(1)
- 正则表达式 分组
- NaN探秘
- 只输出mybatis相关sql语句信息的配置如下
- 编程语言语法学习指南
- 虚拟机安装教程