mybatis源码1.2:mapper接口代理对象的获取
由于我实在是感觉自己功力不够选择跳过 SqlSession sqlSession = sessionFactory.openSession();过段时间再看
接下来开始查看
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
调用Configuration对象得getMapper方法
public <T> T getMapper(Class<T> type) { return this.configuration.getMapper(type, this); }
Configuration得getMapper方法,返回得是Configuration对象中MapperRegistry的getMapper方法,MapperRegistry中使用一个Map(knowMappers)保存了扫描到的mapper接口信息,具体的话保存的就是mapper接口的Class对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return this.mapperRegistry.getMapper(type, sqlSession); }
MapperRegistry中的getMapper方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
/*
* 根据我们调用session.getMapper中传递的Class对象,去map中查找是否存在,map的key就是扫描的的mapper接口的Class对象
* value就是MapperProxyFactory,里面有个mapperInterface成员,保存的也是mapper接口的Class对象
*/
MapperProxyFactory<T> 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); } } }
接下来进入mapperProxyFactory.newInstance方法,MapperProxyFactory是帮我们创建MapperProxy对象,他实现了InvocationHandler接口,这是一个代理类
protected T newInstance(MapperProxy<T> mapperProxy) {
//2,通过Proxy对象来创建代理对象 ,最后拿到mapper接口的代理对象,并返回 return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); } public T newInstance(SqlSession sqlSession) {
//1,创建代理类对象 MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); return this.newInstance(mapperProxy); }
MapperProxy实现了InvocationHandler接口,里面有个invoke方法,当通过Proxy.newProxyInstance生成的代理对象调用真实对象的方法时,会执行该invoke方法
比如:UserMapper mapper = sqlSession.getMapper(UserMapper.class) 调用mapper中的方法时:mapper.getUserById(1) 就会调用invoke,这是关于jdk动态代理的知识
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try {
/*
首先我们得mapper接口时没有实现类的,也就是没有具体的实现方法,里面的方法是不能反射调用的
但是如果是Object中的方法就可以调用
method.getDeclaringClass用来判断当前这个方法是属于哪个类的方法。
动态代理对象是可以调用toString,hashCode等这些从Object对象中继承的方法
如果是调用这类方法的话直接反射调用,
*/ if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } if (method.isDefault()) { return this.invokeDefaultMethod(proxy, method, args); } } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } MapperMethod mapperMethod = this.cachedMapperMethod(method);
//这里大概就是执行db操作的方法了 return mapperMethod.execute(this.sqlSession, args); }
通过sqlSession获取的mapper对象其实时通过jdk的动态代理生成的一个代理对象,mapper接口就是被代理的一方
通过Proxy生成的代理对象调用方法时会调用代理类(MapperProxy)中的invoke方法,