1. Mybatis
本文mybatis源码的分析大致思路围绕着下列代码进行开展的,如下4段代码。
//获取SqlSession工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("Mybatis-Config.xml"));
//工厂生成一个SqlSession会话
SqlSession session = factory.openSession(true);
//获取一个代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//执行sql语句并映射结果集
User user = mapper.selectById(42);
2. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(“Mybatis-Config.xml”));
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
/**
inputStream表示字节输入流的类的超类,通过它来读取xml文件,Resources.getResourceAsStream("Mybatis-Config.xml")
最终返回的是一个BufferedInputStream字节输入流对象,因为无论是类还是xml文件等,都需要被classLoader装载到内存后才能被当前线程使用,
而Mybatis-Config.xml文件其实是被AppClassLoader下的getResourceAsStream方法装载到内存的,
(根据双亲委派原则,AppClassLoader负责加载类路径下的指定内容)
此时的inputStream对象中的数据是字节序列,需要被解析转化
environment和properties此时为均为空对象,将引用传递new XMLConfigBuilder(inputStream, environment, properties);
由于是单例对象引用传递,该构造方法执行结束后,environment和properties均有值
**/
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties)的详细如下:
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
//注:这里new XPathParser(inputStream, true, props, new XMLMapperEntityResolver())
//将inputStream的字节序列数据转换为document节点树对象
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
//初始化一个Configuration对象,成员变量均为初始值
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
补充XPathParser:
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
//XMLInputSource读取字节数组中的数据,最终将其转换为Document节点树对象
//Document对象是org.w3c.dom包下的,Document接口代表整个 HTML 或 XML 文档。 从概念上讲,它是文档树的根,并提供对文档数据的主要访问。。
this.document = createDocument(new InputSource(inputStream));
}
super(new Configuration())
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
//别名注册实例化
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
//类型转化注册器实例化,当数据库映射字段类型和实体类属性类型不一致时,则通过该类型转换器将映射字段类型处理为实体类属性字段
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);执行结束后, XMLConfigBuilder对象具有主要的成员遍历有:实例化完成的Configuration配置对象,此时并未初始化完成,TypeAliasRegistr别名注册器,TypeHandlerRegistry做类型处理注册
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
....省略以下代码
build(parser.parse());
|
XMLConfigBuilder:
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//该方法用于初始化Configuration配置类对象
//parser.evalNode("/configuration")解析document对象为XNode对象(该对象是Mybatis自定义的对象,用于存储document中的Node节点)
parseConfiguration(parser.evalNode("/configuration"));
//此时的configuration初始化完成,返回
return configuration;
}
补充: parseConfiguration(parser.evalNode("/configuration"));
private void parseConfiguration(XNode root) {
try {
//这些字段均为Mybatis配置文件中可配置的标签
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
执行结束后返回一个SqlSessionFactory对象
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
总结:SqlSessionFactoryBuilder()通过读取配置文件转为InputStream对象,再读取该对象转换为Document节点对象,将该对象封装在XPathParser(Mybatis自定义)中,再调用XPathParser的evalNode读取对应的Node节点。再将该节点封装再XNode对象。
为啥这样呢?因为方便接下来build构造SqlSessionFactory更加便捷,通过指定字段读取XNode的指定节点对象,让其封装在特点对象中,如配置文件中的environment标签封装在environment对象中,mappers标签下配置的类路径会使用类加载器加载到内存等待读取,如配置了package name=“com.hnjd.mapper”/ 会去扫描mapper下的接口将其封装在MapperRegistry对象中,内有一个成员变量knownMappers,HashMap的结构,key值为接口的类信息,value值为一个代理对象MapperProxyFactory工厂对象,该对象中封装了相应的Class对象,最终返回一个MapperProxy代理对象,这就是为啥我们可以通过 UserMapper mapper = session.getMapper(UserMapper.class);获取到相应的UserMapper代理对象,就是去MapperRegistry对象中读取的。
最终像environment对象,以及MapperRegistry对象和配置文件中的标签转化的对象,都存放在Configuration对象中,类似在配置文件中configuration是environment和mappers的根标签一样,而Configuration配置类对象又存储在SqlSessionFactory中。
最后可以分析得出:SqlSessionFactory有两件事:1.存放Configuration配置类,2.根据Configuration配置类生产相应的SqlSession。
补充MapperRegister:
3.SqlSession session = factory.openSession(true);
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
//configuration.getDefaultExecutorType()获取默认的执行器
//Configuration中默认的执行器为SIMPLE
//可以通过 <setting name="defaultExecutorType" value="BATCH"/>配置
// protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
//而执行器类型分三种,是枚举的形式(看Mybatis版本所示)
package org.apache.ibatis.session;
public enum ExecutorType {
//策略模式,三种策略
SIMPLE, REUSE, BATCH
}
//根据Mybatis官方文档所述
SIMPLE:普通的执行器
REUSE:重用预处理语句(PreparedStatement)
BATCH:不仅重用语句还会执行批量更新
生产SqlSession的过程如下所示
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//获取 Environment,用于连接数据库,Mybatis底层操作MySQL数据库的方式仍然是JDBC,只不过对结果集映射的处理更加只能了,还有各种拦截器的配合使用,同时可以利用拦截器生成日志了
final Environment environment = configuration.getEnvironment();
//获取事务工厂,为JdbcTransactionFactory,根据Connection用于生产JdbcTransaction
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//JdbcTransaction的事务控制就是封装了下Connection的commit和rollback,当openSession(true)指定为true了,就是使用JdbcTransaction做事务控制,
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//根据事务和执行器类型生成Executor,Mybaits是使用Executor执行SQL语句所以需要事务transaction对象。
final Executor executor = configuration.newExecutor(tx, execType);
//根据Configuration配置类和Executor执行器生成SqlSession对象,以及autoCommit是否由Mybaits管理事务
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
补充: final Executor executor = configuration.newExecutor(tx, execType);执行器的实例化过程
org.apache.ibatis.session.Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
//根据执行器类型生成相应的执行器
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
//Batch类型
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
//REUSE类型
executor = new ReuseExecutor(this, transaction);
} else {
//SIMPLE类型
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
//!无论是那种类型这里都会将其封装到CachingExecutor执行器中,也就是说当调用执行器的方法,会调用CachingExecutor再调用相应类型执行器的方法
executor = new CachingExecutor(executor);
}
//将执行器进行动态代理
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
//补充 executor = (Executor) interceptorChain.pluginAll(executor);
org.apache.ibatis.plugin.InterceptorChain
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
public Object pluginAll(Object target) {
//如果配置了拦截器则调用拦截器内部的plugin方法,plugin会调用Plugin类的warp方法进行动态代理,传入的target方法正是执行器对象
for (Interceptor interceptor : interceptors) {
//循环目的,配置了多少个拦截器就代理几次,类似套娃
target = interceptor.plugin(target);
}
return target;
}
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
.
//补充org.apache.ibatis.plugin.Plugin
//targetCachingExecutor执行器对象
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
//返回代理对象
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
总结:获取SqlSession的过程就是,从factory工厂拿出Configuration配置类,从Configuration拿出Environment生成Transaction事务管理,Trasaction事务对象生成后,根据Tracation和执行器类型生成Executor执行器,最后将Configuration和Execturo执行器和标识事务管理传入SqlSession中返回。
最后分析得出:SqlSession就是根据Executuro执行器和Configuration配置类生成的,而执行器就是根据Trasaction事务管理器生成的,而SqlSesion的作用由于有执行器则可以执行语句,由于有Trasaction则可以管理事务,以及获取映射器(请继续见本文分析)
4.UserMapper mapper = session.getMapper(UserMapper.class);
org.apache.ibatis.session.defaults.DefaultSqlSession
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
org.apache.ibatis.session.Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//这就是加载Configuration通过读取配置文件中Mappers节点封装生成的MapperRegistry
return mapperRegistry.getMapper(type, sqlSession);
}
org.apache.ibatis.binding.MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//key值为接口的类信息,value值为一个代理对象MapperProxyFactory工厂对象,该对象中封装了相应的Class对象,最终返回一个MapperProxy代理对象
//private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
//根据Class类信息获取生成代理对象的工厂MapperProxyFactroy
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
//如果该Class对象并没有在MapperRegistry中注册,或者说是没有在配置文件Mappers中配置,报出该类型并没有被注册的异常信息
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//根据sqlSession通过工厂实例化一个代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
org.apache.ibatis.binding.MapperProxyFactory<T>
public T newInstance(SqlSession sqlSession) {
//根据sqlSession和类信息生成一个MapperProxy对象
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
//调用JDK的代码生成代理对象
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
总结:通过class类信息getMapper的过程就是去Configuration中的MapperRegistry中的Class类信息和MapperProxyFactory工厂的Map对象中根据Class类信息get相应的MapperProxy工厂实例化生成MapperProxy代理对象
5.User user = mapper.selectById(42);
该mapper对象是一个MapperProxy代理对象,请看MapperProxy代理对象中的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
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);
}
//重点在这,上述只是特殊情况的判断
//将Method对象放进methodCache缓存中
final MapperMethod mapperMethod = cachedMapperMethod(method);
//传入SqlSession(因为内部封装了执行器,sql语句的执行需要它),args就是方法参数调用execute
return mapperMethod.execute(sqlSession, args);
}
//补充:
private MapperMethod cachedMapperMethod(Method method) {
//private final Map<Method, MapperMethod> methodCache;
//当方法重复调用时,优先取缓存中取
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
//当方法初次调用时,生成MapperMethod对象放进缓存中,该对象中主要是SqlCommand(封装了类路径和Sql语句的类型,如本文是“SELECT”,策略模式,详细了解请继续看下文所述)和MethodSignature方法签名(判断返回值类型)两个成员变量
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
mapperMethod.execute(sqlSession, args)
org.apache.ibatis.binding.MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
//步骤4.在MapperMethod的SqlCommand中封装的SQL语句类型在这里起作用了,策略模式,本文为查询SELECTE,所以直接看SELECTE
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
//这里条件判断就是根据MapperProxy执行方法后的返回值是什么类型判断的,method为MethodSignature
if (method.returnsVoid() && method.hasResultHandler()) {
//无返回值
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
//返回的是集合等类型的
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
//返回的是Map类型的
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
//流式查询
result = executeForCursor(sqlSession, args);
} else {
//本文返回值是User对象,所以走这
//获取方法入参参数
Object param = method.convertArgsToSqlCommandParam(args);
//执行SqlSession查询单个方法,传入类路径和入参参数
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
请看DefaultSqlSession对象中的SelectOne和selectList方法
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
//statement类路径,parameter入参参数
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) {
//由于是查询单个则返回list集合的第一个元素
return list.get(0);
} else if (list.size() > 1) {
//查询单个,如果查询出的数据数量大于1,则抛出TooManyResultsException异常
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//根据类路径在Configuration的配置类中获取MappedStatement
// protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
//MappedStatement中封装了Configuration和类路径以及sql语句映射xml文件和返回值类型以及sql语句类型还有Sql语句,拦截器就是通过拦截该对象来生成日志的,因为它内部封装了语句执行的所有内容,此时部分属性仍为空,需要后续传入。
MappedStatement ms = configuration.getMappedStatement(statement);
//在SqlSession中调用Executor执行器执行sql语句,由于类型(BATCH,REUSE,SIMPLE)执行器被封装CachingExecutor对象中,而CachingExecutor对象由被动态代理了(本文配置了拦截器),所有会调用Plugin中的invoke方法,优先执行拦截器中的方法.
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//org.apache.ibatis.plugin.Plugin
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//这里的signature指的是拦截器上配置的@Signature注解,signatureMap的key值封装了执行器类信息,value值是根据配置的@Signature注解内的信息封装的Method方法
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
//执行配置拦截器内的intercept方法
return interceptor.intercept(new Invocation(target, method, args));
}
//如果该方法未被拦截则直接返回
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
//补充配置拦截器的代码如下:
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class,
Object.class, RowBounds.class, ResultHandler.class})
})
public class MybatisPlugin implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
String sql = buildMethodArgNameMapAndResultSql(mappedStatement, args);
System.out.println("sql = " + sql);
//根据invocation中的method对象类型执行相应方法,如何又是代理对象则继续执行一遍拦截器方法,当执行到Executor时,结束代理,
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target,this);
}
public void setProperties(Properties properties) {
}
public String buildMethodArgNameMapAndResultSql(MappedStatement mappedStatement, Object[] args){
Map<String,Object> nameArgMap = Maps.newHashMap();
Object parameterValue = null;
if(args.length>1){
//获取参数,if语句成立,表示sql语句有参数,参数格式是map形式
parameterValue = args[1];
}else {
throw new RuntimeException("参数为空");
}
String[] split = parameterValue.toString().substring(1,parameterValue.toString().lastIndexOf('}')).split(",");
String[] names = new String[split.length];
final int[] i = {0};
Arrays.asList(split).forEach(parameter -> {
String name = parameter.substring(0,parameter.lastIndexOf('=')).trim();
String value = parameter.substring(parameter.lastIndexOf('=')+1,parameter.length()).trim();
names[i[0]] = name;
i[0] = i[0] +1;
nameArgMap.put(name,value);
});
BoundSql boundSql = mappedStatement.getSqlSource().getBoundSql(parameterValue);
ParameterMapping parameterMapping = boundSql.getParameterMappings().get(0);
String parameterKey = parameterMapping.getProperty();
System.out.println("parameterKey = " + parameterKey);
String sql = boundSql.getSql();
StringBuilder resultSql = getSql(nameArgMap, sql, names);
return resultSql.toString();
}
public StringBuilder getSql(Map<String,Object> map ,String sql,String[] names){
StringBuilder sb = new StringBuilder();
System.out.println("map:"+map);
System.out.println(sql);
int length =sql.length();
for (int i = 0; i < length; i++) {
char c =sql.charAt(i);
if(c == '?'){
for (int j = 0;j<names.length;j++){
if(sb.indexOf(names[j])!=-1){
sb.append(map.get(names[j]));
names[j] = " ";
}
}
continue;
}
sb.append(sql.charAt(i));
}
return sb;
}
}
CachingExecutor执行器的query方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//根据MappedStatement获取sql语句,以及入参参数
BoundSql boundSql = ms.getBoundSql(parameterObject);
//做一层缓存
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
//使用CachingExecutor的目的就是多次查询时,无需重复访问数据库,Mybatis做了缓存执行器,可以当重复请求时则在该处获取缓存直接返回了
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//deletate则为配置的执行器类型,由于第一次访问,无缓存则直接走配置类型的queyr方法,而Batch和Reuse以及Simple执行器的父类都是BaseExecutor执行器,所以会先走父类
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
BaseExecutor的public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) =>BaseExecutor的 private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)方法
//org.apache.ibatis.executor.BaseExecutor
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
//将sql语句相关信息放进localCache缓存中,当执行BaseExecutor的queyr方法时会先去localCache中取sql语句的信息,取到了直接返回,则无需访问数据库了
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
//BaseExecutor的doQuery方法是一个抽象方法,所以会交给子类执行,此时就到了配置的BatchExecutor(本文环境这样配置的,默认为Simple)出场了
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
//查询结束后将sql语句信息和查询的结果集合封装到localCache中,也就是一级缓存~
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
org.apache.ibatis.executor.BatchExecutor
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
flushStatements();
//获取配置类
Configuration configuration = ms.getConfiguration();
//生成StatementHandler,看下列补充
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
//补充:
org.apache.ibatis.session.Configuration
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//生成statementHandler的目的为了处理statement,请看下列补充2
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//这里的动态代理操作和执行器的动态代理操作一模一样,套娃式代理,配置了几个拦截器就代理几次,最终就调用几次拦截器中的intercept的方法
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
//补充2:
org.apache.ibatis.executor.statement.RoutingStatementHandler
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());
}
}
确定好StatementHandler的类型PreparedStatementHandler后,最终会生成它的父类BaseStatementHandler
org.apache.ibatis.executor.statement.BaseStatementHandler
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//重点在这,当statementHandler的类型确定好后,会生成相应的参数处理器parameterHandler和结果集处理器resultSetHandler
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
//补充:
//生成ParameterHandler和ResultSetHandler的过程同样会进行套娃式动态代理,为了调用拦截器的intercept方法,根据配置的签名拦截相应方法类型
//Configuration中
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
当StatementHandelr实例化完成后,就可以开始准备访问数据库了,回到doQuery方法
org.apache.ibatis.executor.BatchExecutor
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
flushStatements();
//获取配置类
Configuration configuration = ms.getConfiguration();
//生成StatementHandler,看下列补充
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
//获取连接,JDBC操作开始了
Connection connection = getConnection(ms.getStatementLog());
//看补充
stmt = handler.prepare(connection, transaction.getTimeout());
//调用StatementHandler处理生成的statement,其实是调用内部的parameterHandler处理参数看补充2
handler.parameterize(stmt);
//处理完sql语句的参数后,调用StatementHandler的query方法,resultHandelr为null,其实就是调用PreparedStatementHandler中的resultSetHandler对象,将sql语句的执行结果传入进行参数处理
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
//补充:
//调用BaseStatement的prepare方法
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//JDBC操作,操作数据库,生成Statement对象
statement = instantiateStatement(connection);
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
//补充2
org.apache.ibatis.executor.statement.PreparedStatementHandler
@Override
public void parameterize(Statement statement) throws SQLException {
//将方法入参参数代替sql语句中的#{id},这里就不进行深入了,内部就是算法对参数处理
parameterHandler.setParameters((PreparedStatement) statement);
}
继续看Executor的doQuery方法的返回值是handler.query(stmt, resultHandler);中PreparedStatementHandler的query方法
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
//执行sql语句
ps.execute();
//将PreparedStatement传入resultSetHandler进行参数处理
return resultSetHandler.<E> handleResultSets(ps);
}
PreparedStatement中的ResultSet执行结果如下图所示:
继续看ResultSetHandler的handleResultSets方法
org.apache.ibatis.executor.resultset.DefaultResultSetHandler
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
//结果集容器
final List<Object> multipleResults = new ArrayList<Object>();
int resultSetCount = 0;
//处理statement中ResultSet的结果集,将列名和类型读取出来包装在ResultSetWrapper中
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
//映射的实体类对象,实体类中属性所需的类型
ResultMap resultMap = resultMaps.get(resultSetCount);
//将数据库中读取的数据类型rsw和实体类属性的类型resultMap和一个结果集容器(此时为空)传入,此时处理结果集.
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
handleResultSet(rsw, resultMap, multipleResults, null);=>handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);=> handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);均为结果集处理流程
//org.apache.ibatis.executor.resultset.DefaultResultSetHandler
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
skipRows(rsw.getResultSet(), rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
//封装了数据库字段名,实体类属性类型,javaType和jdbcType等信息都封装在该类中,结果集映射
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
//重点在这,结果集处理
Object rowValue = getRowValue(rsw, discriminatedResultMap);
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//返回结果集对象!如果不为空直接返回了,也就是结果集映射结束了,查询出的对象返回。
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
}
return rowValue;
}
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
this.useConstructorMappings = false; // reset previous mapping result
final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
final List<Object> constructorArgs = new ArrayList<Object>();
//!获取结果集对象
Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
// issue gcode #109 && issue #149
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
break;
}
}
}
//设置当前映射结果
this.useConstructorMappings = (resultObject != null && !constructorArgTypes.isEmpty());
return resultObject;
}
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
//返回的对象Class类信息
final Class<?> resultType = resultMap.getType();
//根据类信息和反射工厂生成MetaClass对象
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
//如果返回值对象中使用了参数构造器,构造器中封装的属性类型封装在该List集合中(本文使用了有参构造器)
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
if (hasTypeHandlerForResultObject(rsw, resultType)) {
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
} else if (!constructorMappings.isEmpty()) {
//如果对象的有参构造器不为空,则使用参数构造器创建返回结果集对象。
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
return objectFactory.create(resultType);
} else if (shouldApplyAutomaticMappings(resultMap, false)) {
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
}
throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
boolean foundValues = false;
//根据构造器中的入参参数类型数量遍历,封装在constructorArgs结合中
for (ResultMapping constructorMapping : constructorMappings) {
final Class<?> parameterType = constructorMapping.getJavaType();
final String column = constructorMapping.getColumn();
final Object value;
try {
if (constructorMapping.getNestedQueryId() != null) {
value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
} else if (constructorMapping.getNestedResultMapId() != null) {
final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
value = getRowValue(rsw, resultMap);
} else {
final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
//其实就是根据参数的不同类型去ResultSet中根据列名取值
//如此时是String类型就好在typeHandler下的子类StringTypeHandler中的getNullableResult方法调用ResultSet的getString方法
//(还是JDBC操作)
value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
}
} catch (ResultMapException e) {
throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
} catch (SQLException e) {
throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
}
constructorArgTypes.add(parameterType);
//传入集合中
constructorArgs.add(value);
foundValues = value != null || foundValues;
}
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}
//补充本文的实体类:
@Data
@ToString
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private Timestamp birthday;
private String sex;
private String address;
}
objectFactory.create(resultType, constructorArgTypes, constructorArgs),该方法根据相应实体类中的参数构造器实例化对象。
org.apache.ibatis.reflection.factory.DefaultObjectFactory
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Class<?> classToCreate = resolveInterface(type);
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
<T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> constructor;
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
}
//constructorArgTypes参数类型封装不为空直接走这
//获取参数构造器
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
//调用JDK代码实例化对象,返回对象
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} catch (Exception e) {
StringBuilder argTypes = new StringBuilder();
if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
for (Class<?> argType : constructorArgTypes) {
argTypes.append(argType.getSimpleName());
argTypes.append(",");
}
argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
}
StringBuilder argValues = new StringBuilder();
if (constructorArgs != null && !constructorArgs.isEmpty()) {
for (Object argValue : constructorArgs) {
argValues.append(String.valueOf(argValue));
argValues.append(",");
}
argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
}
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}
此时其实一个完整的返回值对象已经构建完毕,回到DefaultResultSetHandler的createResultObject创建结果集对象这里,
这里存在一个小问题可以参考我的另一篇博客分析:类型处理
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
final Class<?> resultType = resultMap.getType();
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
if (hasTypeHandlerForResultObject(rsw, resultType)) {
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
} else if (!constructorMappings.isEmpty()) {
//执行结束,返回结果集
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
return objectFactory.create(resultType);
} else if (shouldApplyAutomaticMappings(resultMap, false)) {
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
}
throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
此时结果集对象构建完成,ResultSetHandler的工作也完成了,执行结束后会将该对象存储到MetaObject对象中,一路返回到BatchExecutor的doQuery方法
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
flushStatements();
Configuration configuration = ms.getConfiguration();
// StatementHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
//ResultSetHandler
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
//此时一个完整对象已经构造完成了,源码分析结束。
总结:通过调用MapperProxy代理对象的invoke方法确定SQL语句的类型,调用SqlSession的相应方法,SqlSession会去调用Executor执行器,但由于使用了拦截器,执行器已被Plugin对象中的wrap方法调用创建了代理对象,所以会走Plugin对象的invoke方法,调用拦截器的intercept方法,然后才会去执行CachingExecutor缓存执行器的方法,如query查询,优先去缓存中取,如果换成中有执行结果则直接返回,没有则调用相应的执行器取执行sql语句,Executor会去创建一个StatementHandler对象,StatementHandler对象中封装了Preparestatement和ResultsetHandler对象,Preparestatement用于处理sql语句的参数,ResultSetHandler用于处理statement执行完后的ResultSet结果集对象,最终返回相应的实体类对象。返回到Executo执行器中,将返回结果作为value值放进localCache一级缓存中,方法的类路径和执行语句等信息作为key值,下次访问当调用执行器时,会先检测localCache中是否有该方法的缓存,有则直接返回不做数据库访问了。
6.后言
大总结下:
mybatis的执行流程就是:根据配置文件生成一个Configuration配置类对象从而构建出一个SqlSessionFactory工厂,该工厂通过实例化一个执行器Executor并确定执行器的类型,将执行器放入CachingExecutor执行器中(委托模式),若配置了拦截器,此时还会调用Plugin对象的wrap方法进行动态代理生成代理对象和事务控制器Trasacation生成一个SqlSesson对象,再从MapperRegister注册器中根据类信息取出注册的MapperProxyFactory工厂,再由该工厂根据SqlSession生产了一个并进行了一层动态代理mapperProxy对象,调用mapperProxy对象会优先执行MapperProxy中的invoke方法,根据策略模式,调用sqlsession的相应方法,然后会去让Executor去执行sql语句,如果是SELECT类型同时又需要处理参数,它会创建一个statementHandler对象,若有拦截器配置,该对象同样会被动态代理,同时实例化Preparestatement和ResultSetHandler对象,同样,若有拦截器配置,这两个同样会被动态代理(此时可以得知,Mybatis拦截器可以在执行器执行时,预处理SQL语句时,处理返回集结果时配置签名进行拦截),Preparestatement用于预处理SQL语句,ResultSetHandler用于处理ResultSet执行sql语句后数据库返回的数据,处理完后,放入localCache一级缓存中,这就是Mybatis的基本执行流程。
谢谢阅读,如有错误,还请斧正。