篇章一:入口篇
我们学习Mybatis时知道其核心是SqlSessionFactory,它是mybatis的核心类,也是Mybatis运行的入口,spring集成mybatis时需要配置SqlSessionFactoryBean和扫描mapper的MapperScannerConfigurer,spring-mybatis集成主要的配置就这么点,从这理解也就不难理解mybatis入口问题了,但是<bean>节点只是指明了该类的路径和一些属性信息,并没有指明先运行哪个方法呀?我们带着问题【SqlSessionFactoryBean是入口,那入口方法是哪个?】继续研究下去,
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations"
value="classpath:com/jianlejun/mapper/*.xml" />
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="mapUnderscoreToCamelCase" value="true" />
</bean>
</property>
</bean>
<!--扫描dao -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.jianlejun.dao" />
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory"></property>
</bean>
我们点进去看看SqlSessionFactoryBean.
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (failFast && event instanceof ContextRefreshedEvent) {
// fail-fast -> check all statements are completed
this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
}
}
}
可以看到SqlSessionFactoryBean实现了三个接口:
1.ApplicationListener接口:里面只有一个onApplicationEvent方法,有什么用呢?看官方的注释,它是基于观察者模式创建的,当上下文ApplicationContext加载完实现了该接口的bean后,负责通知该bean,bean接收到通知后(onApplicationEvent方法),可以在方法内做自己的逻辑处理,简单点理解就是容器你好,我收到你加载我完毕的通知了,接下里就交给我吧,不用你操心了。
很显然这不是我们要找的方法入口,因为bean都加载完了,说明mybatis配置文件什么都处理完了,那我们再来看看InitializingBean接口
2.InitializingBean接口:接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法(如果bean配置了init-method属性,afterPropertiesSet优先级高于init-method)。
由上可知,这就是我们要找的入口了,spring在初始化bean时,会先调用afterPropertiesSet()方法,从上面代码可知,它在里面调用了buildSqlSessionFactory()方法,哎,最上面我们是不是说了mybatis的核心是SqlSessionFactory,可想而知,这个构造SqlSessionFactory的方法buildSqlSessionFactory()是最核心的方法了。
入口篇完。
篇章二:配置篇
1.配置文件加载
Mybatis配置bean时注入了一个mapperLocations属性,指明项目xml mapper文件的路径,SqlSessionfactoryBean内定义了一个Resource数组接收mapperLocations的位置
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations"
value="classpath:com/jianlejun/com/mapper/*.xml" />
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="mapUnderscoreToCamelCase" value="true" />
</bean>
</property>
</bean>
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private Resource configLocation;
private Configuration configuration;
private Resource[] mapperLocations;
/**
* Set locations of MyBatis mapper files that are going to be merged into the {@code SqlSessionFactory}
* configuration at runtime.
*
* This is an alternative to specifying "<sqlmapper>" entries in an MyBatis config file.
* This property being based on Spring's resource abstraction also allows for specifying
* resource patterns here: e.g. "classpath*:sqlmap/*-mapper.xml".
*/
public void setMapperLocations(Resource[] mapperLocations) {
this.mapperLocations = mapperLocations;
}
}
2.读取配置文件
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
//省略了前面次要代码
if (!isEmpty(this.mapperLocations)) {
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
}
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
}
}
}
这段代码主要根据mapperLocation的文件流构造XMLMapperBuilder(解析xml文件的核心类),然后调用XMLMapperBuilder的parse()方法进行xml文件解析,点进去看看parse()方法体
public class XMLM

本文详细分析了MyBatis的入口SqlSessionFactoryBean,揭示了其初始化过程,以及配置文件加载和解析的过程。通过配置篇,讲解了mapperLocations属性、XMLMapperBuilder的parse()方法解析XML配置文件,特别是<resultMap>和<sql|select|update|insert|delete>节点的解析。最后在应用篇中,探讨了MyBatis如何通过MapperProxy调用DAO方法,执行SQL并进行结果映射。

1463

被折叠的 条评论
为什么被折叠?



