mybatis的生命周期包含4部分:
1. SqlSessionFactoryBuilder
2.SqlSessionFactory
3.SqlSession
4.Mapper
mybatis的运行是先根据相关的配置文件通过SqlSessionFactoryBuilder构建SqlSessionFactory,在根据SqlSessionFactory去创建响应的SqlSession,SqlSession在根据Mapper传递的sql,进行相关的动作,返回结构给Mapper.
构建SqlSessionFactory过程:
第一步:
通过 org.apache. ibatis. builder.xmL.XMLConfigBuilder解析配置的XML文件,读出配置参数,并将读取的数据存入这个org.apache ibatis session. Configuration类中。注意MyBatis几乎所有的配置都是存在这里的。
第二步:
使用 Confinguration对象去创建 SqlSession Factory。 My Batis中的 SqlSession Factory是一个接口,而不是实现类,为此 My Batis提供了一个默认的 Sqlsession Factory实现类,我们般都会使用它 org.apache ibatis session. defaults. Defaultsqlsession Factory。注意,在大部分情况下我们都没有必要自己去创建新的 Sqlsession Factory的实现类。
Configuration 源码:
public class Configuration {
protected Environment environment;
protected boolean safeRowBoundsEnabled;
protected boolean safeResultHandlerEnabled;
protected boolean mapUnderscoreToCamelCase;
protected boolean aggressiveLazyLoading;
protected boolean multipleResultSetsEnabled;
protected boolean useGeneratedKeys;
protected boolean useColumnLabel;
protected boolean cacheEnabled;
protected boolean callSettersOnNulls;
protected boolean useActualParamName;
protected boolean returnInstanceForEmptyRow;
protected String logPrefix;
protected Class<? extends Log> logImpl;
protected Class<? extends VFS> vfsImpl;
protected LocalCacheScope localCacheScope;
protected JdbcType jdbcTypeForNull;
protected Set<String> lazyLoadTriggerMethods;
protected Integer defaultStatementTimeout;
protected Integer defaultFetchSize;
protected ExecutorType defaultExecutorType;
protected AutoMappingBehavior autoMappingBehavior;
protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
protected Properties variables;
protected ReflectorFactory reflectorFactory;
protected ObjectFactory objectFactory;
protected ObjectWrapperFactory objectWrapperFactory;
protected boolean lazyLoadingEnabled;
protected ProxyFactory proxyFactory;
。。。。。。
Configuration作用:
1. 读入配置文件,包括基础配置的XML文件和映射器的XML文件。
2.初始化基础配置,比如 My Batis的别名等,一些重要的类对象,例如,插件、映射器、 ObjectFactory和 type Handler对象
3.提供单例,为后续创建 SessionFactory服务并提供配置的参数执行一些重要的对象方法,初始化配置信息。
在第一步中Mybatis会读取所有的xml文件,将其初始化保存到 Configuration类的单例对象中,初始化包含了:properties全局参数,settings设置,typeAliases别名,typeHandler类型处理器,ObjectFactory对象,plugin插件,environment环境,DatabaseldProvider数据库标识,Mapper映射器。
sqlSessionFactory=new SqlSessionFactoryBuilder(). build(inputstream).
org.apache.ibatis.session.SqlSessionFactoryBuilder中的builder方法。
MyBatis会根据 Configuration的配置读取所配置的信息,构建 SqlsessionFactory对象。
SqLSession运行过程:
探究其原理的了解一下 Mapper映射原理。
Mapper映射器:构建需要执行的Sql脚本。由三部分组成:
1. MappedStatement,它保存映射器的一个节点( select|insert|delete|update)。包括许多我们配置的SQL、SQL的id、缓存信息、 resultMap、 parameterType、 resultType、languageDriver等重要配置内容。
2.SqLSource,它是提供 BoundS对象的地方,它是 MappedStatement的一个属性。
3. BoundSql,它是建立SQL和参数的地方。它有3个常用的属性:SQL、 parameterObject ,parameterMappings。
Mapper映射是通过动态代理实现的。
/**
* Copyright 2009-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.binding;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.ibatis.session.SqlSession;
/**
* @author Lasse Voss
*/
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
//动态代理对Mapper接口实行了代理模式,而代理的方法都放置到了MapperProxy类中了
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
package org.apache.ibatis.binding;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.SqlSession;
/**
动态代理模式
* @author Clinton Begin
* @author Eduardo Macarron
*/
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 {
//判断它是否是一个类,显然这里 Mapper是一个接口不是类,所以判定失败
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, 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;
}
}
上面运用了 invoke方法。一旦 mapper是一个代理对象,那么它就会运行到 invoke方法里面, invoke首先判断它是否是一个类,显然这里 Mapper是一个接口不是类,所以判定失败。那么就会生成 MapperMethod对象,它是通过 cachedMapperMethod方法对其初始化的,然后执行 execute方法,把 sqlsession和当前运行的参数传递进去。
Mapper执行的过程是通过 Executor、 StatementHandler、Parameter Handler和 Resulthandler来完成数据库操作和结果返回的。
Executor代表执行器,由它来调度 Statementhandler、 ParameterHandler、 Resulthandler等来执行对应的SQL。
StatementHandler的作用是使用数据库的 Statement( PreparedStatement)执行操作,它是四大对象的核心,起到承上启下的作用。
ParameterHandler用于SQL对参数的处理。
Resulthandler是进行最后数据集( Resultset)的封装返回处理的。
Executor执行器:创建执行器首先根据Configuration获取执行器类型。
在创建sqlSession就开始初始化:
生成指定的执行器。
public class SimpleExecutor extends BaseExecutor {
。。。。。。。。。。。。。。。。。。。。。。。。。。。。
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
。。。。。。。。。。。。。。。。。。。。。。。。。。
}
显然 MyBatis根据 Configuration来构建 Statementhandler,然后使用 prepareStatement方法,对SQL编译并对参数进行初始化,我们在看它的实现过程,它调用了 Statementhandler的prepare()进行了预编译和基础设置,然后通过 StatementHandler的 parameterize()来设置参数并执行, resulthandler再组装査询结果返回给调用者来完成一次查询。
数据库会话器 StatementHandler:专门处理数据库会话的。
创建会话器:
RoutingStatementHandler不是我们真实的服务对象,它是通过适配模式找到对应的StatementHandler来执行的。在MyBatis中, StatementHandler和 Executor一样分为三种SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler它所对应的是三种执行器。
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
我们最常用的是PreparedStatementHandler:
预编译
预编译完成就需要开始设置参数。
ParameterHandler:
设置完参数就需要开始查询了,进行结构封装。
Resulthandler:
/**
* Copyright 2009-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.resultset;
import org.apache.ibatis.cursor.Cursor;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* @author Clinton Begin
*/
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
实现:
结果封装返回。
SqlSession运行原理图: