spring-mybatis源码分析

上文中我们初略的了解了mybatis源码工作流程 但是它是如何集成到spring中来工作的 先看示例代码:

applicationMybatis.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
	xmlns:jee="http://www.springframework.org/schema/jee" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
		
		<!-- 配置spring-mybatis.xml -->
		<context:property-placeholder location="classpath:config/application.properties"/>
		
		<!-- 配置数据库连接池 -->
		<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
			<property name="driverClassName" value="${jdbc.driver}"/>
			<property name="url" value="${jdbc.url}"/>
			<property name="username" value="${jdbc.username}"/>
			<property name="password" value="${jdbc.password}" />
		</bean>
		
		<!-- 配置MyBatis的SessionFactory -->
		<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
			<property name="dataSource" ref="dataSource"/>
<!-- 			<property name="mapperLocations" value="classpath:mapper/*.xml"/> -->
		</bean>
		
		<bean id="myMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
		  <property name="mapperInterface" value="com.lgj.mybatis.xml.dao.MyMapper" />
		  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
		</bean>

		
</beans>

dao:

public interface MyMapper {
	
	@Select("select now() ")
	String getDate();
	
	@Insert("insert into test values ('我输入的测试啊啊啊')")
	void insertTest();

}

启动main方法:

public class MybatisTest {

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationMybatis.xml");
		MyMapper bean = applicationContext.getBean(MyMapper.class);
		System.out.println(bean.getDate());
		bean.insertTest();
	}

}

spring的启动流程我们暂不关注  

我们看到MyMapper的bean配置在xml中

class是org.mybatis.spring.mapper.MapperFactoryBean  是一个fatorybean

factorybean在spring启动时候会创建两个实例  一个是它本身  一个是getObject方法 创建出来的示例  直接看getObject源码

public T getObject() throws Exception {
    //1、getSqlSession 拿到sqlSession对象
    //2、getMapper 生成mapper的代理类
    return getSqlSession().getMapper(this.mapperInterface);//mapperInterface在xml中传入  
  }
public SqlSession getSqlSession() {
    return this.sqlSessionTemplate;//其实就是传入的sqlSessionTemplate对象  也就是我们可以传入sqlSessionTemplate对象 但xml中我们传入的是sqlSessionFactory 查看父类
  }

org.mybatis.spring.support.SqlSessionDaoSupport.setSqlSessionFactory(SqlSessionFactory)
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
      this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);//通过sqlSessionFactory 创建了sqlSessionTemplate 对象
    }
  }

protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    return new SqlSessionTemplate(sqlSessionFactory);//创建了SqlSessionTemplate实例
  }

也就是getSqlSession拿到了SqlSessionTemplate对象  getMapper也是它的方法

org.mybatis.spring.SqlSessionTemplate.getMapper(Class<T>)

public <T> T getMapper(Class<T> type) {
    return getConfiguration().getMapper(type, this);//type就是interface this是SqlSessionTemplate对象
  }

 public Configuration getConfiguration() {
    return this.sqlSessionFactory.getConfiguration();//也就是sqlSessionFactory的Configuration对象 这个对象哪里创建的 后面会说
  }

org.apache.ibatis.session.Configuration.getMapper(Class<T>, SqlSession)
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);//通过mapperRegistry 拿到mapper  sqlSession是SqlSessionTemplate
  }

org.apache.ibatis.binding.MapperRegistry.getMapper(Class<T>, SqlSession)
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);//通过mapperProxyFactory实例化  sqlSession是SqlSessionTemplate
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

org.apache.ibatis.binding.MapperProxyFactory.newInstance(SqlSession)
public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);//创建代理类MapperProxy
    return newInstance(mapperProxy);//实例化方法
  }

org.apache.ibatis.binding.MapperProxyFactory.newInstance(MapperProxy<T>)
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);//我们可以查看mapperProxy的增强方法 invoke方法 mapperProxy就是MapperProxy对象
  }


org.apache.ibatis.binding.MapperProxy.invoke(Object, Method, Object[])
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {//方法是Object的方法
        return method.invoke(this, args);
      } else {//走else
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }


org.apache.ibatis.binding.MapperProxy.cachedInvoker(Method)
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
    try {
      return MapUtil.computeIfAbsent(methodCache, method, m -> {
        if (m.isDefault()) {//java8的default方法  走else
          try {
            if (privateLookupInMethod == null) {
              return new DefaultMethodInvoker(getMethodHandleJava8(method));
            } else {
              return new DefaultMethodInvoker(getMethodHandleJava9(method));
            }
          } catch (IllegalAccessException | InstantiationException | InvocationTargetException
              | NoSuchMethodException e) {
            throw new RuntimeException(e);
          }
        } else {
          return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));//创建PlainMethodInvoker对象  查看他的invoke方法
        }
      });
    } catch (RuntimeException re) {
      Throwable cause = re.getCause();
      throw cause == null ? re : cause;
    }
  }


org.apache.ibatis.binding.MapperProxy.PlainMethodInvoker.invoke(Object, Method, Object[], SqlSession)
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
      return mapperMethod.execute(sqlSession, args);//执行execute方法
    }

org.apache.ibatis.binding.MapperMethod.execute(SqlSession, Object[])
public Object execute(SqlSession sqlSession, Object[] args) {//我们以select为例
    Object result;
    switch (command.getType()) {
      case INSERT: {//insert
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {//update
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {//delete
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);//最终调用了sqlSession的selectOne 但是这个sqlSession是sqlSessionTemplate对象 我们要看其中的selectOne方法
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        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;
  }

最终的查询方法调用了org.mybatis.spring.SqlSessionTemplate.selectOne(String, Object)方法

public <T> T selectOne(String statement, Object parameter) {
    return this.sqlSessionProxy.selectOne(statement, parameter);//sqlSessionProxy在构造函数中被创建
  }

org.mybatis.spring.SqlSessionTemplate.SqlSessionTemplate(SqlSessionFactory)
    org.mybatis.spring.SqlSessionTemplate.SqlSessionTemplate(SqlSessionFactory, ExecutorType)
        org.mybatis.spring.SqlSessionTemplate.SqlSessionTemplate(SqlSessionFactory, ExecutorType, PersistenceExceptionTranslator)
        public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    notNull(executorType, "Property 'executorType' is required");

    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
    this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class }, new SqlSessionInterceptor());//sqlSessionProxy 是一个代理类 增强方法位于SqlSessionInterceptor中 查看它的invoke方法
  }

org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor.invoke(Object, Method, Object[])
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);//拿到Mybatis真正的sqlSession对象  DefaultSqlSession
      try {
        Object result = method.invoke(sqlSession, args);//method是selectOne 反射调用DefaultSqlSession的selectOne方法
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {//事务判断
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;//返回结果
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator
              .translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

总结一下:

1、MapperFactoryBean作用

  1.1、创建了sqlSession对象:SqlSessionTemplate

  1.2、实现了InitializingBean afterPropertiesSet中 往configuration中添加了mapper,内部创建MapperProxyFactory 后续getMapper来创建代理类

  1.3、实现了FactoryBean ,getObject方法生成了代理类的bean:MapperProxy

2、SqlSessionTemplate作用

  2.1、代理DAO MapperProxy在执行方法时候 通过command类型找到SqlSessionTemplate中对应的方法

  2.2、SqlSessionTemplate创建了代理对象sqlSessionProxy,其中的增强器SqlSessionInterceptor的invoke才是真正的执行方法

  2.3、SqlSessionInterceptor中 拿到MyBatis的DefaultSqlSession对象 通过反射调用其中的方法 

  2.4、通过反射调用mybatis中的DefaultSqlSession对应方法

3、SqlSessionFactoryBean对象

  3.1、实现了FactoryBean getObject创建了SqlSessionFactory对象

  3.2、实现了InitializingBean afterPropertiesSet 创建sqlSessionFactory

  3.3、创建了Configuration对象

  3.4、设置了传入的dataSource

  3.5、解析所有的mybatis的xml文件装载到Configuration当中

  3.6、创建DefaultSqlSessionFactory工厂 来创建DefaultSqlSession

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值