在后续分析Mybatis 流程中代码的可能会用到IDEA debug 技巧:
- 条件断点
代码断点,右键 勾选弹窗 Condition : 写入表达式
-
回到上一步:
-
Java动态代理实现 InvocationHandler接口:
package com.lvyuanj.core.test;import com.lvyuanj.core.model.User;
import org.apache.ibatis.annotations.Select;import java.util.List;public interface UserTestMapper {@Select("select * from t_user")public List<User> query();
}
package com.lvyuanj.core.test;import org.apache.ibatis.annotations.Select;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("query db:"+ method.getAnnotation(Select.class).value()[0]);return null;}}
package com.lvyuanj.core.test;import java.lang.reflect.Proxy;public class MyQueryTest {public static void main(String[] args) {Class[] clazz = {UserTestMapper.class};UserTestMapper userTestMapper = (UserTestMapper) Proxy.newProxyInstance(MyQueryTest.class.getClassLoader(), clazz, new MyInvocationHandler());userTestMapper.query();}
}
mybatis 核心FactoryBean
MapperScannerRegistrar
实现了ImportBeanDefinitionRegistrar 接口。 可以自动注入
MapperScannerConfigurer 实现 BeanDefinitionRegistryPostProcessor这个类
postProcessBeanDefinitionRegistry()中扫描注入mapper
MapperFactoryBean 实现了FactoryBean 也继承了SqlSessionDaoSupport 类;
Spring 管理MapperFactoryBean 的时候设置属性的时候初始化SqlSessionTemplate
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);}}
需要的SqlSessionFactory 在AppConfig中定义,由于SqlSessionFactoryBean实现FactoryBean接口类,factoryBean.getObject(); 获取到真实的对象SqlSessionFactory
在创建对象的时候时候进行afterPropertiesSet(); 对象
public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource());return factoryBean.getObject();
}
当开发者调用userMapper.selectAll() 方法的时候,由于userMapper是MapperFactoryBean 工厂bean创建的Bean的时候调用的是MapperFactoryBean.getObject(); 最终调用org.apache.ibatis.binding.MapperRegistry#getMapper(Class type, SqlSession sqlSession)
方法中调用 mapperProxyFactory.newInstance(sqlSession)
@Overridepublic T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);}
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);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}
protected T newInstance(MapperProxy<T> 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);}
SqlSessionTemplate 是SqlSession 的实现类,
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());}
@Overridepublic <T> T selectOne(String statement, Object parameter) {return this.sqlSessionProxy.selectOne(statement, parameter);}/*** {@inheritDoc}*/@Overridepublic <K, V> Map<K, V> selectMap(String statement, String mapKey) {return this.sqlSessionProxy.selectMap(statement, mapKey);}/*** {@inheritDoc}*/@Overridepublic <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {return this.sqlSessionProxy.selectMap(statement, parameter, mapKey);}......
代理类
private class SqlSessionInterceptor implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);try {Object result = method.invoke(sqlSession, args);if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { //是否启用事务管理,没有事务管理mybatis自己管理// 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 #22closeSqlSession(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);}}}}
开始涉及MyBatis SqlSession部分的一些机制,关于MyBatis sqlSession的一点整理,SqlSession主要是MyBatis定义的用于进行持久化操作的对象,对connection进行了包装。在上面Spring Transaction的机制中,我们获取到了connection,之后会首先调用SqlSessionUtils里面的getSession方法,判断当前的sqlSessionHolder以及是否存在事务锁定。
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);SqlSession session = sessionHolder(executorType, holder);if (session != null) {return session;}LOGGER.debug(() -> "Creating a new SqlSession");session = sessionFactory.openSession(executorType);registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);return session;}
sessionFactory.openSession(executorType); sessionFactory上文中在sqlSessionFactoryBean 实现InitializingBean接口初始化的时候afterPropertiesSet() 方法被调用
this.sqlSessionFactory = buildSqlSessionFactory(); 执行是new DefaultSqlSessionFactory()对象。
@Overridepublic SqlSession openSession(ExecutorType execType) {return openSessionFromDataSource(execType, null, false);}private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor = configuration.newExecutor(tx, execType);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 TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); 获取事务工厂类,第一次的时候new ManagedTransactionFactory();
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); 创建一个事务对象
final Executor executor = configuration.newExecutor(tx, execType);
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor executor;if (ExecutorType.BATCH == executorType) {executor = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {executor = new SimpleExecutor(this, transaction);}if (cacheEnabled) {executor = new CachingExecutor(executor);}executor = (Executor) interceptorChain.pluginAll(executor);return executor;}
UserMapper 初始化到调用链流程图