1、mybatis架构设计
mybatis架构三层作用是什么呢
Api接口层:提供API 增加、删除、修改、查询等接口,通过API接口对数据库进行操作。
数据处理层:主要负责SQL的 查询、解析、执行以及结果映射的处理,主要作用解析sql根据调用请求完成一次数据库操作.
架构基础层:负责通用基础服务支撑,包含事务管理、连接池管理、缓存管理等共用组件的封装,为上层提供基础服务支撑.
2、mybatis层次结构图解
mybatis每个组件作用是什么呢?
3、mybatis源码解析
sql一次执行流程如何实现的?
首先从SqlSessionFactory 与 SqlSession执行流程说起
先看看session是如何获取的,上图:
第一步:SqlSessionFactoryBuilder读取配置文件,XMLConfigBuilder.parseConfiguration真正解析xml 源码如下:
/*** 构建XMLConfigBuilder 解析mybatis的配置文件* 创建DefaultSqlSessionFactory*/public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try { // 构建 XMLConfigBuilder, XMLConfigBuilder 解析mybatis的配置文件 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 解析XML 构建 DefaultSqlSessionFactory 对象 return build(parser.parse());} catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { }}}
第二步:build方法构建DefaultSqlSessionFactory
/** * 创建 DefaultSqlSessionFactory 对象 * @param config Configuration 对象 * @return DefaultSqlSessionFactory 对象 */public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); //构建者设计模式}
第三步:当取SqlSessionFactory之后,可以通过SqlSessionFactory获取SqlSession对象。源码如下:
/*** 1、进入openSessionFromDataSource* 2、ExecutorType 为Executor的类型,TransactionIsolationLevel为事务隔离级别,autoCommit是否开启事务* 3、openSession的多个重载方法可以指定获得的SeqSession的Executor类型和事务的处理*/private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try { // 获取Environment 对象 final Environment environment = configuration.getEnvironment(); // 构建Transaction 对象 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 构建 Executor 对象 final Executor executor = configuration.newExecutor(tx, execType); // 构建 DefaultSqlSession 对象 return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) { // 如异常,则关闭 Transaction 对象 closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);} finally { ErrorContext.instance().reset();}}
SqlSession已经拿到,接下来我们做什么呢,不错就是执行sql 增、删、改查了,那如何读取呢接一下来介绍一下MapperProxy
MapperProxy代理接口
代理接口调用方法案例:
// 使用JDK动态代理对mapper接口产生代理对象IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);//代理对象调用接口中的任意方法,执行的都是动态代理中的invoke方法List<Object> allUser = mapper.findAllUser();
如上图可知:通过MapperProxy动态代理接口, 当执行自己写的IUserMapper里面的findAllUser方法的时候,其实是对应的mapperProxy在代理。具体看一下如何获取MapperProxy对象的
第一步:通sqlSession.getMapper方法从Configuration获取 源码如下:
@Overridepublic <T> T getMapper(Class<T> type) {return configuration.getMapper(type, this);}
第二步:MapperRegistry代理源码如下:
@SuppressWarnings("unchecked")public <T> T getMapper(Class<T> type, SqlSession sqlSession) {// 获得 MapperProxyFactory 对象final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);// 不存在,则抛出 BindingException 异常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);}}
第三步:MapperProxyFactory源码如下:
@SuppressWarnings("unchecked")protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);}//MapperProxyFactory类中的newInstance方法public T newInstance(SqlSession sqlSession) {// 创建了JDK动态代理的invocationHandler接口的实现类mapperProxyfinal MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);// 调用了重载方法return newInstance(mapperProxy);}
通过以上的动态代理,就可以方便地使用IUserMapper 接口啦:
IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
最终看一下sql具体是怎么执行的吧 上图:
上图已基本说明sql执行流程了,接下来源码演示
第一步:MapperProxy是如何实现的呢?源码展示:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 如果是 Object 定义的方法,直接调用
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);
}
// 获得 MapperMethod 对象
final MapperMethod mapperMethod = cachedMapperMethod(method);
// 重点在这:MapperMethod最终调用了执行的方法
return mapperMethod.execute(sqlSession, args);
}
第二步:MapperMethod.execute是如何实现的呢?以查询为例子源码展示:
public Object execute(SqlSession sqlSession, Object[] args) {Object result;//判断mapper中的方法类型,最终调用的还是SqlSession中的方法 switch (command.getType()) { //...由于篇幅 省略 case INSERT case UPDATE case DELETE:代码 //重点看查询为例子展示:case SELECT: if (method.returnsMany()) { result = executeForMany(sqlSession, args); // 执行查询,返回 Map } else { // 转换参数 Object param = method.convertArgsToSqlCommandParam(args); // 查询单条 result = sqlSession.selectOne(command.getName(), param); if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { result = Optional.ofNullable(result); } } break;default: throw new BindingException("Unknown execution method for: " + command.getName()); }// 返回结果return result;}
第三步:executeForMany 参数封装,源码展示:
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {List<E> result;// 转换参数Object param = method.convertArgsToSqlCommandParam(args);// 执行 SELECT 操作if (method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.selectList(command.getName(), param, rowBounds);} else { result = sqlSession.selectList(command.getName(), param);}// issue #510 Collections & arrays support// 封装 Array 或 Collection 结果if (!method.getReturnType().isAssignableFrom(result.getClass())) { if (method.getReturnType().isArray()) { // 情况一,Array return convertToArray(result); } else { return convertToDeclaredCollection(sqlSession.getConfiguration(), result); // 情况二,Collection }}// 直接返回的结果return result; // 情况三,默认}
第四步:执行sql返回结果集:
@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {//拼装sql String sql = boundSql.getSql(); // 执行查询 statement.execute(sql); // 处理返回结果 return resultSetHandler.handleResultSets(statement);}
到此Mybatis源码分析完毕~
1、mybatis框架中应用哪些模式呢
mybatis架构应用到模式汇总如下:
今天分享就到这,感谢大家能读完此文章,希望对你有所帮助~