Mybatis3-架构和源码

一:架构

1、架构理解:

mybatis架构主要分为三层:

1、接口层: 提供api接口,也就是mapper相关。

        包含:sqlSession

2、数据处理层: 处理数据的。 将参数组装生成动态sql,执行后将结果封装返回。

        包含:Executor,StatementHandler,ParameterHandler,ResultSetHandler,

        TypeHandler,MappedStatement,BoundSql,SqlSource(负责根据⽤户传递的parameterObject,动态地⽣成SQL语句,将信息封装到BoundSql)

3、支撑层:底层事务、链接、缓存等管理。 为处理层做支撑。

2、执行流程:

a、容器启动

        加载并解析配置文件到Configuration(可以基于注解或xml文件)。

        将sql配置信息加载到MappedStatement。

b、api调用

        通过调用mapper接口,传入参数。

        通过mapper接口的全路径,对应着mapper.xml中namespace + id,确定statementid,  找到sql。

        解析生成动态的sql并执行。

        将结果封装并返回。

二:mybatis源码解析 

在之前已简单写过持久层框架,只是读取了个别标签配置。 在mybatis中有很多的标签,现在来看一下:

原生api调用流程

1、初始化流程:

首先我们会读取xml,创建SqlSessionFactory。

Inputstream inputstream = Resources.getResourceAsStream("mybatis-config.xml");
//这⼀⾏代码正是初始化⼯作的开始。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSessionFactory就是mybatis提供的,这里开始进入源码。

build方法经过重载,最终到以下方法:

 parser.parse()创建了Configuration,里面都包含了一些什么信息:

 如上,解析了很多的标签,包括之前手写过的mappers标签。

对于mappers中的每一个mapper.xml,都会解析成一个个的MappedStatement,具体对应着一个个的select/update/insert/delete节点,最终存放在Configuration中

Map < String , MappedStatement > mappedStatements = new StrictMap < MappedStatement > ( "Mapped Statements collection" )

2、sql执行流程:

sql的执行是先通过获取SqlSession开始,然后调用它提供的api:

SqlSession sqlSession = factory.openSession();
List<User> list = sqlSession.selectList("com.mapper.UserMapper.getUserByName");

SqlSession通常与ThreadLocal绑定,⼀个会话使⽤⼀ 个 ,使用完后需要调用close()关闭。 

openSession():

    public SqlSession openSession() {
//getDefaultExecutorType传递的是SimpleExecutor
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
    }

openSessionFromDataSource():

/**
*ExecutorType 为Executor的类型,TransactionIsolationLevel为事务隔离级别, 
*autoCommit是否开启事务;    
*openSession的多个重载⽅法可以指定获得的SeqSession的Executor类型和事务的处理
*/

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            //根据参数创建指定类型的Executor
            Executor executor = this.configuration.newExecutor(tx, execType);
            //返回DefaultSqlSession
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

获取sqlSession后,进入selectList方法,有多个重载方法: 

public <E> List<E> selectList(String statement) {
        return this.selectList(statement, (Object)null);
    }

    public <E> List<E> selectList(String statement, Object parameter) {
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
    }

    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
//根据传⼊的全限定名+⽅法名从映射的Map中取出MappedStatement对象
            MappedStatement ms = this.configuration.getMappedStatement(statement);
//调⽤Executor中的⽅法处理
 //RowBounds是⽤来逻辑分⻚
 // wrapCollection(parameter)是⽤来装饰集合或者数组参数
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
        } finally {
            ErrorContext.instance().reset();
        }

        return var5;
    }

最终调用的是Executor的查询方法

进入Executor:

//此⽅法在SimpleExecutor的⽗类BaseExecutor中的实现
 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//根据传⼊的参数动态获得SQL语句,最后返回⽤BoundSql对象表示
        BoundSql boundSql = ms.getBoundSql(parameter);
//为本次查询创建缓存的Key
        CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
        return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }


//重载方法开始查询
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
        if (this.closed) {
            throw new ExecutorException("Executor was closed.");
        } else {
            if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
                this.clearLocalCache();
            }

            List list;
            try {
                ++this.queryStack;
                list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
                if (list != null) {
                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                } else {
//如果缓存中没有本次查找的值,那么从数据库中查询
                    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
                }
            } finally {
                --this.queryStack;
            }

            if (this.queryStack == 0) {
                Iterator var8 = this.deferredLoads.iterator();

                while(var8.hasNext()) {
                    BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
                    deferredLoad.load();
                }

                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }

            return list;
        }
    }
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

        List list;
        try {
//查询的⽅法
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            this.localCache.removeObject(key);
        }
//放入缓存
        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }

 真正执行doQuery()是在实现类中

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;

        List var9;
        try {
            Configuration configuration = ms.getConfiguration();
//传⼊参数创建StatementHanlder对象来执⾏查询。 之前介绍过插件四大对象,都是生成的代理对象。
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//创建jdbc中的statement对象
            stmt = this.prepareStatement(handler, ms.getStatementLog());
// StatementHandler 进⾏查询处理
            var9 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }

        return var9;
    }

 看看prepareStatement方法:

    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
      //获取连接。经过重重调⽤最后会调⽤openConnection⽅法,从连接池中获得连接
        Connection connection = this.getConnection(statementLog);
        //使用StatementHandler准备Statement(待会儿再来看)
        Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
        handler.parameterize(stmt);
        return stmt;
    }



//从连接池datasource获取连接
protected void openConnection() throws SQLException {
        if (log.isDebugEnabled()) {
            log.debug("Opening JDBC Connection");
        }

        this.connection = this.dataSource.getConnection();
        if (this.level != null) {
            this.connection.setTransactionIsolation(this.level.getLevel());
        }

        this.setDesiredAutoCommit(this.autoCommmit);
    }

 Executor.query()⽅法⼏经转折,最后会创建⼀个StatementHandler对象,然后将必要的参数传 递给 StatementHandler来完成对数据库的查询,最终返回List结果集。

经过以上步骤可以看出, Executor的作用:
1 、根据传递的参数,完成 SQL 语句的动态解析,⽣成 BoundSql 对象,供 StatementHandler 使⽤;
2 、为查询创建缓存,以提⾼性能
3 、创建 JDBC Statement 连接对象,执行查询 ,返回 List 查询结果。

 在executor中真正的查询是给了StatementHandler,StatementHandler主要完成了两件事:

1、创建JDBC的PreparedStatement对象,并对sql中的问号占位符用参数替换,生成可执行sql。

2、通过List query方法完成执行Statement,将db返回结果封装成list返回。

进⼊到 StatementHandler parameterize(statement):

public void setParameters(PreparedStatement ps) {
        ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());

//之前我们自己实现过boundSql,知道这里存放了解析后的sql和所有参数名的映射。
//sql中的每个?对应着一个ParameterMapping(ParameterMapping存放着当前的参数名是什么,类型等)
        List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
        if (parameterMappings != null) {
            for(int i = 0; i < parameterMappings.size(); ++i) {
                ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    String propertyName = parameterMapping.getProperty();
                    Object value;
                    if (this.boundSql.hasAdditionalParameter(propertyName)) {
                        value = this.boundSql.getAdditionalParameter(propertyName);
                    } else if (this.parameterObject == null) {
                        value = null;
                    } else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
                        value = this.parameterObject;
                    } else {
                        MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
                        value = metaObject.getValue(propertyName);
                    }

// 每⼀个 Mapping都有⼀个 TypeHandler,根据 TypeHandler 来对 preparedStatement
进⾏设置参数
                    TypeHandler typeHandler = parameterMapping.getTypeHandler();
                    JdbcType jdbcType = parameterMapping.getJdbcType();
                    if (value == null && jdbcType == null) {
                        jdbcType = this.configuration.getJdbcTypeForNull();
                    }

                    try {
                        typeHandler.setParameter(ps, i + 1, value, jdbcType);
                    } catch (TypeException var10) {
                        throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var10, var10);
                    } catch (SQLException var11) {
                        throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var11, var11);
                    }
                }
            }
        }

    }

经过以上方法完成了参数设置,进入实现类PreparedStatementHandler的查询:

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
//.使⽤ ResultSetHandler 来处理 ResultSet
        return this.resultSetHandler.handleResultSets(ps);
    }
public List<Object> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());

//多ResultSet的结果集合,每个ResultSet对应⼀个Object对象。
//⽽实际上,每 个 Object 是List<Object> 对象。
//在不考虑存储过程的多ResultSet的情况,普通的查询,实际就⼀个ResultSet,
//也就是说,multipleResults最终最多就⼀个元素。
        List<Object> multipleResults = new ArrayList();
        int resultSetCount = 0;
//获得⾸个ResultSet对象,并封装成ResultSetWrapper对象
        ResultSetWrapper rsw = this.getFirstResultSet(stmt);
//在不考虑存储过程的多ResultSet的情况,普通的查询,实际就⼀个ResultSet,也 就是说,
resultMaps就⼀个元素
        List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        this.validateResultMapsCount(rsw, resultMapCount);

        while(rsw != null && resultMapCount > resultSetCount) {
            ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);

//处理ResultSet,将结果添加到multipleResults中
            this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
           //获取下一个(不考虑存储过程,普通查询就只有一个,这里为null,会跳出循环)
 rsw = this.getNextResultSet(stmt);
            this.cleanUpAfterHandlingResultSet();
            ++resultSetCount;
        }

//因为'mappedStatement.resultSets'只在存储过程中使⽤,本系列暂时不考虑,忽略即可
        String[] resultSets = this.mappedStatement.getResultSets();
        if (resultSets != null) {
            while(rsw != null && resultSetCount < resultSets.length) {
                ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
                if (parentMapping != null) {
                    String nestedResultMapId = parentMapping.getNestedResultMapId();
                    ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
                    this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
                }

                rsw = this.getNextResultSet(stmt);
                this.cleanUpAfterHandlingResultSet();
                ++resultSetCount;
            }
        }

 //如果是multipleResults单元素,则取⾸元素返回
        return this.collapseSingleResultList(multipleResults);
    }


上面解析了sqlSession调用原生api的流程。  实际使用不会直接这样调用,而是通过动态代理获取Mapper。

mapper调用流程

mapper使用方法:

public static void main(String[] args) {
    //前三步都相同
    InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = factory.openSession();
    //这⾥不再调⽤SqlSession的api,⽽是获得了接⼝对象,调⽤接⼝中的⽅法。
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> list = mapper.getUserByName("tom");
 }

MapperRegistryConfiguration中的⼀个属性,它内部维护了一个HashMap存放mapper接口和对应的工厂类,一个mapper对应一个工厂类。

mybatis 初始化除了把mapper.xml中解析成一个个的MappedStatement对象,还会根据配置的mapper接口扫描路径,对每一个mapper创建对应的MapperProxyFactory,作为map中的value,key是当前mapper的字节码对象

public class MapperRegistry {
    private final Configuration config;
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();

//省略……

//添加接口
public <T> void addMapper(Class<T> type) {
        if (type.isInterface()) {
            if (this.hasMapper(type)) {
                throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
            }

            boolean loadCompleted = false;

            try {
//为每一个mapper接口创建MapperProxyFactory
                this.knownMappers.put(type, new MapperProxyFactory(type));
                MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
                parser.parse();
                loadCompleted = true;
            } finally {
                if (!loadCompleted) {
                    this.knownMappers.remove(type);
                }

            }
        }

    }

调用 sqlSession.getMapper(UserMapper.class)时,调用了Configuration中的getMapper

    
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }

接着调用了MapperRegistry中的

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        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中
//MapperProxy实现了InvocationHandler,使用jdk动态代理
protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(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) {
        //传⼊了 SqlSession,说明每个session中的代理对象的不同的!
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
//如果是Object定义的⽅法,直接调⽤
            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 mapperMethod = this.cachedMapperMethod(method);
//重点在这:MapperMethod最终调⽤了执⾏的⽅法
        return mapperMethod.execute(this.sqlSession, args);
    }

最终的execute方法:

public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        Object param;
        switch(this.command.getType()) {
//判断当前mapper执行的⽅法类型
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
//command.getName()得到的就是当前方法的全路径,也就是statementid,底层调用executor执行。
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            break;
        case UPDATE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
            break;
        case DELETE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
            break;
        case SELECT:
            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else if (this.method.returnsCursor()) {
                result = this.executeForCursor(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
                if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                    result = Optional.ofNullable(result);
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + this.command.getName());
        }

        if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
            return result;
        }
    }

spring整合后,创建的mapper和sqlSession有多少个?

从上面的源码我们知道mapper是创建的动态代理,mapper和sqlSession都是每次创建新的。

与spring整合后,通过注入的方式,不再是先获取sqlSession调用sqlSession.getMapper(UserMapper.class), 而是通过注入,那时候,mapper代理对象就是单例了。  而且创建mapper代理对象时,通过SqlSessionTemplate来创建的(也是实现了jdk动态代理InvocationHandler)。 在它的invoke方法中,每一次调用时才来创建新的sqlSession。    也就是mapper是唯一的一个,sqlSession每次请求时创建。

具体的spring中再说。

猜你喜欢

转载自blog.csdn.net/growing_duck/article/details/124808334