org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
写在前面:Mapper接口对象时通过org.mybatis.spring.mapper.MapperFactoryBean#getObject方法创建的。
org.mybatis.spring.mapper.MapperFactoryBean#getObject
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// 通过SqlSessionFactoryBean对象的getObject创建SqlSessionFactory
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
........
return factory.getObject();
}
// 创建 SqlSessionTemplate对象
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
}
org.mybatis.spring.SqlSessionFactoryBean#getObject
class : org.mybatis.spring.SqlSessionFactoryBean
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
// 会创建 configLocation对象作为sqlSessionFactory的属性
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
@Override
public void afterPropertiesSet() throws Exception {
// 创建sqlSessionFactory
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final Configuration targetConfiguration;
..........
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
class: org.apache.ibatis.session.SqlSessionFactoryBuilder#build(org.apache.ibatis.session.Configuration)
public SqlSessionFactory build(Configuration config) {
// SqlSessionFactory实质是 DefaultSqlSessionFactory
return new DefaultSqlSessionFactory(config);
}
小结:自动配置类中,创建两大对象(DefaultSqlSessionFactory和SqlSessionTemplate),交给spring容器管理。
SqlSessionFactory(DefaultSqlSessionFactory)创建过程:解析mapper.xml,创建configuration对象,交给SqlSessionFactory对象。configuration是DefaultSqlSessionFactory对象的属性。
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
......
}
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {}
说明:MapperScan注解中,是通过import注解导入MapperScannerRegistrar.class。而MapperScannerRegistrar(Mapper扫描注册器)实现了ImportBeanDefinitionRegistrar接口。所以spring启动时,会调用该接口的registerBeanDefinitions方法给spring容器注册bean definitions。也就是个beanDefinitonMap中加入beanDefinition
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
......
// 扫描
scanner.doScan(StringUtils.toStringArray(basePackages));
}
}
org.mybatis.spring.mapper.ClassPathMapperScanner#doScan
// 扫描类 ---> 创建BeanDefinitions ---> 注册到beanDefinionMap中 ---> 修改BeanDefinitions
class: org.mybatis.spring.mapper.ClassPathMapperScanner extends ClassPathBeanDefinitionScanner
@Override
public Set doScan(String... basePackages) {
// 通过指定的包路径,扫描mapper接口,创建BeanDefinition
Set beanDefinitions = super.doScan(basePackages);
.......
processBeanDefinitions(beanDefinitions);
.......
return beanDefinitions;
}
org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions
private MapperFactoryBean> mapperFactoryBean = new MapperFactoryBean
小结:
1. 在MapperScannerRegistrar#registerBeanDefinitions中,通过ClassPathMapperScanner的doScan方法,扫描指定包下面的mapper接口,创建beanDefition加入到beanDefinitionMap中,(key是接口名首字母小写)。再通过processBeanDefinitions 将beandefinition的 BeanClass 改成 MapperFactoryBean.class。
beanDefinitionMap
key = "mapper接口名称,首字母小写"
value=beanDefinition(beanClass=MapperFactoryBean.class)
1. spring遍历beanDefinionMap时,会创建MapperFactoryBean对象。并加入到单例池中。
2. 一般我们都会将mapper对象注入到Service中。那么当service对象在创建时,发现依赖mapper,则会从ioc容器中获取Mapper对象。因为单例池中存放了maper接口和MapperFactoryBean对象的映射关系。所以很一定会获取到MapperFactory对象(MapperFactoryBean实现了FactoryBean接口),再调用其getObject方法,创建mapper接口对象。mapper代理对象实质是通过MapperFactoryBean#getObject方法创建的
public class MapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {
org.mybatis.spring.mapper.MapperFactoryBean#getObject
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
org.mybatis.spring.support.SqlSessionDaoSupport#getSqlSession
public SqlSession getSqlSession() {
return this.sqlSessionTemplate;
}
// 装配SqlSessionTemplate
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
说明: MapperFactoryBean继承了SqlSessionDaoSupport类,且MapperFactoryBean的definition的autowireMode属性为AbstractBeanDefinition.AUTOWIRE_BY_TYPE。所以在创建MapperFactoryBean对象时,已经通过set方式装配了sqlSessionTemplate对象。且sqlSessionTemplate持有了DefaultSqlSessionFactory对象。
org.mybatis.spring.mapper.MapperFactoryBean#getObject
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
org.mybatis.spring.SqlSessionTemplate#getMapper
@Override
public T getMapper(Class type) {
return getConfiguration().getMapper(type, this);
}
org.apache.ibatis.session.Configuration#getMapper
//MapperRegistry mapperRegistry映射器是configuration的属性
public T getMapper(Class type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
org.apache.ibatis.binding.MapperRegistry#getMapper
@SuppressWarnings("unchecked")
public T getMapper(Class type, SqlSession sqlSession) {
// knownMappers保存了接口类型和mapperProxyFactory接口的关系
// 创建Configuration对象的阶段 通过XMLMapperBuilder解析将关系保存到knownMappers
// knownMappers("接口class对象", new MapperProxyFactory()<接口class对象>)
final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) knownMappers.get(type);
......
// 通过该方法创建 Mapper接口代理对象
return mapperProxyFactory.newInstance(sqlSession);
......
}
class: org.apache.ibatis.binding.MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
final MapperProxy mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
class: org.apache.ibatis.binding.MapperProxyFactory
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy mapperProxy) {
// 通过jdk代理创建对象, 入参接口的classLoad, 接口的calss对象, MapperProxy(实现了InvocationHandler)
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
小结:
获取MapperProxyFactory,从MapperRegistry mapperRegistry映射器的knownMappers属性中获取。
通过mapperProxyFactory.newInstance(sqlSession)创建代理对象。(使用的是jdk代理,mapperProxy实现了invocationHandler接口)
mapepr接口的方法执行,实质调用的是mapperProxy#invoke方法。
通过自动配置类MybatisAutoConfiguration,创建DefaultSqlSessionFactory和sqlSessionTemplate对象。(创建过程中解析了mapper.xml)
解析xml中,给Map
扫描maper接口,注册beanDefinitions。进而创建MapperFactoryBean对象。
通过MapperFactoryBean#getObject方法,在knownMappers 找到MapperProxyFactory工厂对象创建maper代理对象。