结合Mybatis源码说说sqlSession创建流程和从中用到的一些设计模式
-
1 UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
-
读取配置文件,生成Configuration对象,其中包含数据源、事务、mapper文件资源以及影响数据库行为属性settings;
-
SqlSessionFactoryBuilder通过读取Configuration对象,生成SqlSessionFactory(构建者模式);
1 public SqlSessionFactory build(Reader reader, String environment, Properties properties) { 2 SqlSessionFactory var5; 3 try { 4 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); 5 var5 = this.build(parser.parse()); 6 } catch (Exception var14) { 7 throw ExceptionFactory.wrapException("Error building SqlSession.", var14); 8 } finally { 9 ErrorContext.instance().reset(); 10 11 try { 12 reader.close(); 13 } catch (IOException var13) { 14 } 15 16 } 17 18 return var5; 19 }
1 private void bindMapperForNamespace() { 2 String namespace = this.builderAssistant.getCurrentNamespace(); 3 if (namespace != null) { 4 Class boundType = null; 5 6 try { 7 boundType = Resources.classForName(namespace); 8 } catch (ClassNotFoundException var4) { 9 } 10 11 if (boundType != null && !this.configuration.hasMapper(boundType)) { 12 this.configuration.addLoadedResource("namespace:" + namespace); 13 this.configuration.addMapper(boundType); 14 } 15 } 16 17 }
1 public SqlSessionFactory build(Configuration config) { 2 return new DefaultSqlSessionFactory(config); 3 }
-
在调用build()方法时,通过XMLConfigBuilder类bindMapperForNamespace()方法,将Mapper接口注册到MapperRegistry类的一个HashMap属性中,key=Mapper.class,value=创建当前Mapper的工厂;
-
通过SqlSessionFactory生成SqlSession实例对象(工厂模式);
-
sqlSession通过getMapper()方法拿到代理对象(代理模式),运用了JDK动态代理,生成了目标Mapper对象的代理对象;
-
通过MapperProxyFactory工厂,生成动态代理的代理类是MapperProxy(工厂模式),实现了InvocationHandler接口,对invoke()方法进行了包装,将非Object类的方法进行了增强,包装成MapperMethod,最后执行execute()方法完成sql增删改查的操作。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { //如果method方法是来自Object的方法,那么直接执行,无需增强; //意思是假如我们执行的是toString()方法,是不需要增强的。 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } if (this.isDefaultMethod(method)) { return this.invokeDefaultMethod(proxy, method, args); } } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } //做了缓存 MapperMethod mapperMethod = this.cachedMapperMethod(method); //执行增删改查操作 return mapperMethod.execute(this.sqlSession, args); }
-