mybatics mapper的注入过程
- 在使用mybatics时,通过MapperScan注解 import registrar MapperScannerRegistrar
- 在MapperScannerRegistrar中会对 ClassPathMapperScanner进行初始化,如setMapperFactoryBean,setSqlSessionTemplateBeanName,setSqlSessionFactoryBeanName等;然后调用ClassPathMapperScanner.doScan方法
- 在doScan方法中会扫描所有的Mapper,并通过MapperFactoryBean生成对应的代理类,然后将该类注册到spring bean factory中,在初始化BeanDefinition时,会通过RuntimeBeanReference添加需要的属性,如sqlSessionTemplate,sqlSessionFactory等,而sqlSessionTemplate,sqlSessionFactory是在MybatisAutoConfiguration中注入到BeanFactory中的。
- MapperFactoryBean继承了SqlSessionDaoSupport,在spring 创建MapperFactoryBean会通过sqlSessionTemplate或sqlSessionFactory生成sqlSession
- 在执行某个mapper时,执行的是动态代理类,代理类为MapperProxy,该类的getObject()方法通过sqlSession.configuration获取对应的mapper
- 在org.apache.ibatis.session.Configuration.getMapper()方法中调用MapperRegistry.getMapper()
- MapperRegistry.getMapper()通过MapperProxyFactory生成对应的代理类,代理类的handler为MapperProxy
- 将该代理类通过factorybean及beandefinition注入到spring 容器中
mapper的执行过程
创建DefaultSqlSession
- 在执行某mapper时,实际执行的是代理类MapperProxy的invoke方法
- 在该类的invoke方法中会调用MapperMethod.execute()方法,在该execute方法中,会根据方法类型(如 select/update/delete等,是由mapper xml标签决定的),执行不同的方法
- 如select方法,接下来会调用SqlSessionTemplate.selectList()方法,然后调用内部类的SqlSessionInterceptor.invoke()方法,此处是动态代理
- 在该invoke()方法中,通过导入的静态方法执行SqlSessionUtils.getSqlSession(),在该方法中会调用DefaultSqlSessionFactory.openSession(ExecutorType execType)方法
- 在openSessionFromDataSource()方法中,会开启事务,并且通过事务及ExecutorType创建Executor,如 SimpleExecutor、ReuseExecutor、CachingExecutor、BatchExecutor
interceptorChain.pluginAll(executor)
以executor为入参调用所有的Interceptor的plugin()方法
- 创建DefaultSqlSession
执行拦截器及Query
- 通过该sqlSession调用其 selectList(String statement, Object parameter)方法,最终会调用executor.query方法
- 该query方法会进入到代理类中,该代理类会执行Executor的mybatics对应的拦截器
- 在拦截器中,当执行invocation.proceed()时,继续执行Executor.query方法
- 在该方法中会进行一些Cache的判断及处理,然后调用queryFromDatabase方法,然后调用doQuery方法
- 在SimpleExecutor.doQuery方法中会调用prepareStatement方法
获取Connection的过程
- SimpleExecutor.prepareStatement中调用父类 BaseExecutor.getConnection()
- BaseExecutor.getConnection()中调用SpringManagedTransaction.getConnection(),然后执行当前类中的openConnection()
- 在方法openConnection()中调用DataSourceUtils.getConnection(this.dataSource)
- 在类DataSourceUtils中最终会通过fetchConnection(dataSource)调用AbstractRoutingDataSource.getConnection()
- 在通过DataSource获取Connection时,实际调用的是AbstractRoutingDataSource.getConnection()方法
- DynamicDataSource继承于AbstractRoutingDataSource
- AbstractRoutingDataSource间接实现了接口DataSource
- 在AbstractRoutingDataSource.getConnection()方法中会调用内部方法determineTargetDataSource()获取DataSource,然后调用该DataSource.getConnection()方法(此处采用装饰模式)
- 在方法determineTargetDataSource()中,会调用该抽象类的抽象方法determineCurrentLookupKey(),然后从targetDataSource中获取该key对应的DataSource(此处使用模板模式)
- 通过上述过程获取到的Connection生成Statement
查询
- 然后调用StatementHandler.query方法
- 之后会进行查询数据库,并封装响应数据