看懂,再整理出来应该就是真明白了。
疑问:MyBatis-Spring集成,spring 是怎么样托管的?
看源码,这个过程应该是这样的:
1.spring配置文件中注册 MapperScannerConfigurer (看参考1),完成scan Mapper并定义为MapperFactoryBean。scan实现参考:Insight context:component-scan 实现class scan。
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor{
// AbstractApplicationContext.invokeBeanFactoryPostProcessors调用 core!
// Invoke factory processors registered as beans in the context.
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 类似context:component-scan 过程,scan指定package的Mapper 接口并注册到beanFactory。
// 1.create Scanner
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setMarkerInterface(this.markerInterface);// addIncludeFilter
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);// PropertyValues
// 2.Scanner.scan 注意super.doScan完成后beanDefinition 的处理
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
}// 自定义 Scanner
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
/**
* Calls the parent search that will search and register all the candidates.
* Then the registered objects are post processed to set them as MapperFactoryBeans
*
*/
@Override
public Set
doScan(String... basePackages) {
Set
beanDefinitions = super.doScan(basePackages);
for (BeanDefinitionHolder holder : beanDefinitions) {
GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean !!!
definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
definition.setBeanClass(MapperFactoryBean.class);
// 配置sqlSessionFactoryBeanName
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
}
//...
}
}
2.在上述Mapper definition 初始化过程中,需要Inject sqlSessionFactory 也就是调用MapperFactoryBean.setSqlSessionFactory()方法。而在此过程中,首先需要初始化sqlSessionFactory(beanFactory 就是自底向上的完成bean的组装、初始化,链式反应,boom)。
public class MapperFactoryBean
extends SqlSessionDaoSupport {
// set 注入
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
// 根据sqlSessionFactory 构造sqlSession
// SqlSessionTemplate 典型的JDK Proxy 应用案例,实现事务的控制 !!!
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
// return an instance of mapperInterface,直接用吧
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
}
3.上述2过程中涉及的sqlSessionFactory初始化
public class SqlSessionFactoryBean {
public void afterPropertiesSet() throws Exception {
// 处理过程类似文档 Building SqlSessionFactory without XML
this.sqlSessionFactory = buildSqlSessionFactory();
}
}
4.至此,MyBatis-Spring 托管解析、初始化完成。
...
参考:
// http://www.mybatis.org/spring/mappers.html
Scanning for mappers
1.Using the
element.
2.Using the annotation @MapperScan
3.Using a classic Spring xml file and registering the MapperScannerConfigurer
// http://www.mybatis.org/mybatis-3/getting-started.html
// demo1: Building SqlSessionFactory without XML
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
// demo2: Acquiring a SqlSession from SqlSessionFactory
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}