Mybatis集成到Spring原理

Spring中集成Mybatis主要有两个难点,一是事务的集成,二是Mapper接口注册到Spring容器中,Spring中集成Mybatis需要引入mybatismybatis-spring依赖包。

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>

通过配置导入将SqlSessionFactoryBean注册到Spring容器中,以及通过@MapperScan@MapperScans确定将哪些Mapper接口注册到Spring容器中。

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@MapperScan(basePackages = {"com.eleven.icode.ispring.mapper"})
public class MyBatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws IOException {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
return factoryBean;
}
}

SqlSessionFactoryBean是一个FactoryBean,且重写了getObjectType方法将代理的Bean的类型设置为了原始的SqlSessionFactory类型,且其实现了InitializingBean接口,主要逻辑都在其实例化完成时调用的afterPropertiesSet(),其作用就是创建Mybatis的SqlSessionFactory,其可以代替全局配置文件,若设置了配置文件可对配置文件内容做一个补充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
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(); // 通过sqlSessionFactoryBuilder来构建我们的sqlSessionFactory
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final Configuration targetConfiguration; // 声明一个Configuration对象用于保存mybatis的所有的配置信息
XMLConfigBuilder xmlConfigBuilder = null;
// 初始化configuration对象,和设置其 `configuration.variables` 属性
if (this.configuration != null) {
// 把配置的SqlSessionFactoryBean配置的configuration赋值给targetConfiguration
targetConfiguration = this.configuration;
if (targetConfiguration.getVariables() == null) {
targetConfiguration.setVariables(this.configurationProperties);
} else if (this.configurationProperties != null) {
targetConfiguration.getVariables().putAll(this.configurationProperties);
}
}
else if (this.configLocation != null) { // 创建xml配置构建器对象,对全局配置文件mybatis-config.xml配置文件进行解析
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
} else {
targetConfiguration = new Configuration();
// 判断configurationProperties不为空,则调用targetConfiguration.set方法把configurationProperties注入到Configuration对象中
Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
}
Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);
// typeAliasesPackage配置情况分为二种:在mybaits-config.xml中配置,在配置SqlSessionFactoryBean时配置
if (hasLength(this.typeAliasesPackage)) {
// 扫描typeAliasesPackage包路径下所有实体类class类型进行过滤注册到Configuration的别名映射器中
scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
.filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface())
.filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
}
// 判断SqlSessionFactory是否配置了typeAliases,一般typeAliasesPackage配置了就没有必要配置typeAliases,注册到Configuration的别名映射器中
if (!isEmpty(this.typeAliases)) {
Stream.of(this.typeAliases).forEach(typeAlias -> { targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);});
}
// 把自定义的插件注册到的mybatis的配置类上
if (!isEmpty(this.plugins)) {
Stream.of(this.plugins).forEach(plugin -> { targetConfiguration.addInterceptor(plugin);});
}
// 扫描自定义的类型处理器(用来处理的java类型和数据库类型的转化) 并且注册到的 targetConfiguration(批量注册)
if (hasLength(this.typeHandlersPackage)) {
scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
.filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
.forEach(targetConfiguration.getTypeHandlerRegistry()::register);
}
if (!isEmpty(this.typeHandlers)) { // 通过配置<TypeHandlers></TypeHandlers>的形式来注册的类型处理器对象
Stream.of(this.typeHandlers).forEach(typeHandler -> { targetConfiguration.getTypeHandlerRegistry().register(typeHandler);});
}
// Mybatis从3.2开始支持可插拔的脚本语言,因此可插入一种语言的驱动来写基于这种语言的动态SQL查询
if (!isEmpty(this.scriptingLanguageDrivers)) {
Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> { targetConfiguration.getLanguageRegistry().register(languageDriver);});
}
Optional.ofNullable(this.defaultScriptingLanguageDriver).ifPresent(targetConfiguration::setDefaultScriptingLanguage);


if (this.databaseIdProvider != null) { // 设置数据库厂商
try {
targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
} catch (SQLException e) {
throw new NestedIOException("Failed getting a databaseId", e);
}
}
Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache); // 若二级缓存不为空,注册二级缓存
if (xmlConfigBuilder != null) {
try {
xmlConfigBuilder.parse(); // 真正的解析的配置(mybatis-config.xml)的document对象
} catch (Exception ex) {
throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
} finally {
ErrorContext.instance().reset();
}
}
// 为的configuration设置一个环境变量
targetConfiguration.setEnvironment(new Environment(this.environment, this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory, this.dataSource));
if (this.mapperLocations != null) { // 循环遍历解析mapper.xml文件
if (this.mapperLocations.length == 0) {
} else {
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
xmlMapperBuilder.parse(); // 真正的解析mapper.xml文件
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
}
}
}
return this.sqlSessionFactoryBuilder.build(targetConfiguration); // 通过建造者模式构建的SqlSessionFactory对象 默认是DefaultSqlSessionFactory
}
private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType) throws IOException {
Set<Class<?>> classes = new HashSet<>();
// 把的多个配置报路径转换成字符串数组
String[] packagePatternArray = tokenizeToStringArray(packagePatterns, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for (String packagePattern : packagePatternArray) { // 循环的包路径
// 把包路径下的class解析成的Resouce数组
Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class");
for (Resource resource : resources) {
try {// 挨个解析成的class类型
ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
if (assignableType == null || assignableType.isAssignableFrom(clazz)) { // 判断当前的class类型是不是被支持
classes.add(clazz); // 加入到结合中
}
} catch (Throwable e) {
LOGGER.warn(() -> "Cannot load the '" + resource + "'. Cause by " + e.toString());
}
}
}
return classes;
}
public Class<? extends SqlSessionFactory> getObjectType() {
return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
}
}

事务集成

事务集成是在SqlSessionFactoryBean中完成的,在为configuration设置环境变量时创建传入SpringManagedTransactionFactory,在Mybatis中是使用的ManagedTransactionFactory创建一个ManagedTransaction,其是直接从DataSource中获取的Connection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
}
public class ManagedTransactionFactory implements TransactionFactory {
public Transaction newTransaction(Connection conn) {
return new ManagedTransaction(conn, closeConnection);
}
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new ManagedTransaction(ds, level, closeConnection);
}
}
public class ManagedTransaction implements Transaction {
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}
protected void openConnection() throws SQLException {
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
}

SpringManagedTransactionFactory中创建的是SpringManagedTransaction,起获取的数据库连接是通过DataSourceUtils工具类从事务同步管理器TransactionSynchronizationManager中获取的连接,从而达到与Spring事务集成的目的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SpringManagedTransactionFactory implements TransactionFactory {
public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
return new SpringManagedTransaction(dataSource);
}
}
public class SpringManagedTransaction implements Transaction {
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}
private void openConnection() throws SQLException {
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
}
}

Mapper接口注册

Mapper接口扫描是通过@MapperScan@MapperScans注解中导入了MapperScannerRegistrar来完成的,Mapper接口注册到Spring容器中是借助FactoryBean来完成的,注解中设置了factoryBean注册Mapper接口的默认值为MapperFactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends Annotation> annotationClass() default Annotation.class;
Class<?> markerInterface() default Class.class;
String sqlSessionTemplateRef() default "";
String sqlSessionFactoryRef() default "";
Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
String lazyInitialization() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.RepeatingRegistrar.class)
public @interface MapperScans {
MapperScan[] value();
}

MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar在容器扫描BeanDefinition时会调用registerBeanDefinitions。其作用其实就是为容器注册一个或多个MapperScannerConfigurer以及给该类设置一些从@MapperScan注解上解析出来的属性。@MapperScans注解上可以配置多个@MapperScan注解在导入时通过RepeatingRegistrar遍历注册多个MapperScannerConfigurer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 从传入的配置类中解析@MapperScan注解信息,把MapperScan注解的属性转化为AnnotationAttributes类型
AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) { // 若上一步解析出来的mapperScanAttrs不为空,说明配置类上加了@MapperScan注解
// 调用重写的方法registerBeanDefinitions#generateBaseBeanName(importingClassMetadata, 0)即将注册的bean定义的名称进行处理
registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
}
}
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
// 创建bean定义构造器通过够构造器来构建出的bean定义<MapperScannerConfigurer>应用到的设计模式[建造者模式]
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
// 手动为MapperScannerConfigurer开启processPropertyPlaceHolders属性为true,需要着重研究下MapperScannerConfigurer类的继承结构
builder.addPropertyValue("processPropertyPlaceHolders", true);
// 为的MapperScannerConfigurer解析@MapperScanner指定扫描的的注解类型
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
builder.addPropertyValue("annotationClass", annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) { // 是否配置了标记接口
builder.addPropertyValue("markerInterface", markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) { // 是否设置了MapperScannerConfigurer的beanName生成器对象
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
}
// 解析@MapperScan注解属性MapperFactoryBean设置到MapperScannerConfigurer声明一个自定义的MapperFactoryBean返回一个代理对象
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
}
// 解析@MapperScan的sqlSessionTemplateRef到底使用是哪个sqlSessionTemplate设置到MapperScannerConfigurer多数据源的情况下需要指定
String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
if (StringUtils.hasText(sqlSessionTemplateRef)) {
builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
}
// 解析@MapperScan的sqlSessionFactoryRef属性 设置到 MapperScannerConfigurer 多数据情况下的话 ,需要指定使用哪个 sqlSessionFactory
String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
if (StringUtils.hasText(sqlSessionFactoryRef)) {
builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
}
// 解析@MapperScan扫描的的包或者是class对象
List<String> basePackages = new ArrayList<>();
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
String lazyInitialization = annoAttrs.getString("lazyInitialization");
if (StringUtils.hasText(lazyInitialization)) {// 指定MapperScannerConfigurer是否为懒加载
builder.addPropertyValue("lazyInitialization", lazyInitialization);
}
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
registry.registerBeanDefinition(beanName, builder.getBeanDefinition()); // 为的容器中注册了MapperScannerConfigurer的接口
}
private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
}
static class RepeatingRegistrar extends MapperScannerRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScansAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName()));
if (mapperScansAttrs != null) {
AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value");
for (int i = 0; i < annotations.length; i++) {
registerBeanDefinitions(annotations[i], registry, generateBaseBeanName(importingClassMetadata, i));
}
}
}
}
}

MapperScannerConfigurer中显示创建了ClassPathMapperScanner包扫描器对象,其继承自ClassPathBeanDefinitionScanner,其作用是为了扫描@MapperScan注解中配置包路径下的目标类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders(); // 若MapperScannerConfigurer属性的processPropertyPlaceHolders为ture时则执行processPropertyPlaceHolders(),解析动态参数
}
// 显示的new一个ClassPathMapperScanner包扫描器对象该对象继承了spring的ClassPathBeanDefinitionScanner为了扫描器指定@MapperScan属性
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
scanner.registerFilters(); // 注册扫描规则过滤器
// 真正的去扫描@MapperScan指定的路径下的bean定义信息,先会去调用ClassPathMapperScanner.scan()方法
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
private void processPropertyPlaceHolders() {
// 因为postProcessBeanDefinitionRegistry是为注册bean定义的,但注册bean定义时需要解析${basepackaage},但PropertyResourceConfigurer类型的bean定义还没有实例化成bean对象 ,故不能提供解析${basepackaage}的能力
// 故显示的设置processPropertyPlaceHolders为ture,即想通过applicationContext.getBeansOfType(PropertyResourceConfigurer.class),提前把PropertyResourceConfigurer组件实例化出来从而解析${basepackaage}
Map<String, PropertyResourceConfigurer> prcs = applicationContext.getBeansOfType(PropertyResourceConfigurer.class);

// 判断PropertyResourceConfigurer的集合不为空,且applicationContext是ConfigurableApplicationContext
if (!prcs.isEmpty() && applicationContext instanceof ConfigurableApplicationContext) {
// 通过名称去容器中获取MapperScannerConfigurer组件
BeanDefinition mapperScannerBean = ((ConfigurableApplicationContext) applicationContext).getBeanFactory().getBeanDefinition(beanName);
// PropertyResourceConfigurer类没有暴露任何的方法来处理的property placeholder substitution即${basepackaage},有且只有提供一个BeanFactoryPostProcessor接口来处理的bean定义
// 但调用BeanFactoryPostProcessor.postProcessBeanFactory()方法需要一个beanFactory,若从外面传入一个Ioc的容器进来会提前破坏ioc容器,故这里创建了一个临时的ioc容器,然后把mapperScannerBean注册到该临时ioc容器中
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition(beanName, mapperScannerBean);
for (PropertyResourceConfigurer prc : prcs.values()) {
prc.postProcessBeanFactory(factory); //这时就可以大胆放心的处理临时的ioc容器factory中的bean定义,即当前的mapperScannerBean
}
PropertyValues values = mapperScannerBean.getPropertyValues(); // 处理完之后重新获取通过PropertyResourceConfigurer解析后的mapperScannerBean的属性
this.basePackage = updatePropertyValue("basePackage", values); // 更新MapperScannerBean属性可能有${}包裹的字段
this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values);
this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values);
this.lazyInitialization = updatePropertyValue("lazyInitialization", values);
}
this.basePackage = Optional.ofNullable(this.basePackage).map(getEnvironment()::resolvePlaceholders).orElse(null);
this.sqlSessionFactoryBeanName = Optional.ofNullable(this.sqlSessionFactoryBeanName).map(getEnvironment()::resolvePlaceholders).orElse(null);
this.sqlSessionTemplateBeanName = Optional.ofNullable(this.sqlSessionTemplateBeanName).map(getEnvironment()::resolvePlaceholders).orElse(null);
this.lazyInitialization = Optional.ofNullable(this.lazyInitialization).map(getEnvironment()::resolvePlaceholders).orElse(null);
}
}

首先会根据在@MapperScan注解上设置的注解类annotationClass、以及markerInterface来添加过滤器,若未设置将会将包下的所有接口扫描出来。

在调用超类ClassPathBeanDefinitionScanner的scan方法扫描包时会调用子类ClassPathMapperScanner中的doScan,而该类又去调用了超类doScan方法,但有一点不同的是这复写了isCandidateComponent方法只扫描接口,而Spring中默认恰好相反。

当将所有符合条件的Mapper接口BeanDefinition信息扫描出来后,进行遍历将beanClass设置成MapperFactoryBean的Class,从而达到偷天换日将Mapper接口通过MapperFactoryBean来创建生成Bean。因为接口是不能被实例化生成Bean的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
public void registerFilters() { // 注册扫描规则过滤器
boolean acceptAllInterfaces = true;
// 若annotationClass不为空,表示用户设置了此属性,则根据此属性生成过滤器以保证达到用户想要的效果,而封装此属性的过滤器就是 AnnotationTypeFiter,其保证在扫描对应Java文件时只接受标记有注解为annotationClass的接口
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}
// 如果markerlnterface不为空,表示要根据此属性生成过滤器以保证达到用户想要的效果,而封装此属性的过滤器就是实现AssignableTypeFiter接口的局部类,扫描过程中只有实现markerIntrface接口的接口才会被接受
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}
if (acceptAllInterfaces) { // 若接受所有接口,则添加自定义INCLUDE过滤器TypeFilter,全部返回true
// default include filter that accepts all classes
addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
}
// 对于命名为package-info Java文件,默认不作为逻辑实现接口,将其排除掉,使用TypeFiltler接口的局部类实现match 法
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); // 调用父类ClassPathBeanDefinitionScanner来进行扫描
if (beanDefinitions.isEmpty()) { // 若扫描后mapper包下有接口类,则扫描bean定义就不会为空
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions); // 这里是将Mapper接口注册到Spring容器中的关键
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) { // 循环所有扫描出mapper的bean定义出来
definition = (GenericBeanDefinition) holder.getBeanDefinition(); // 获取的bean定义
String beanClassName = definition.getBeanClassName(); // 获取的bean定义的名称
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // 设置ConstructorArgumentValues会通过构造器初始化对象
// 进行真的偷天换日操作,将当前Bean的Class设置成MapperFactoryBean的Class
definition.setBeanClass(this.mapperFactoryBeanClass);
definition.getPropertyValues().add("addToConfig", this.addToConfig);
// 为的Mapper对象绑定sqlSessionFactory引用,实际上是为MapperFactoryBean添加一个sqlSessionFactory的属性
// 然后SpringIoc在实例化MapperFactoryBean时为通过populate()为UserMapper(MapperFactoryBean)的sqlSessionFactory属性赋值,调用set方法
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}

if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { // 同上sqlSessionFactory
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); // 将sqlSessionTemplate通过AUTOWIRE_BY_TYPE自动装配
explicitFactoryUsed = true;
}
// 设置UserMapper<MapperFactoryBean>定义的注入模型是通过包扫描进来的,所有默认注入模型为AutowireCapableBeanFactory.AUTOWIRE_NO=0标识通过@Autowire注解注入
// 因为字段上是没有@AutoWired注解,则MapperFactoryBean的字段属性永远自动注入不了值,故需要把UserMapper<MapperFactoryBean>bean定义的注入模型给改成的AUTOWIRE_BY_TYPE=1表示根据类型自动装配
if (!explicitFactoryUsed) {
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization); // 设置bean定义的加载模型(是否为懒加载)
}
}
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}

对于MapperFactoryBean代码就比较简单了,上面在给BeanDefinition设置属性时,给构造函数参数列表中添加了一个参数即原始Mapper类名,故实例化MapperFactoryBean时会调用有参构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
public Class<T> getObjectType() {
return this.mapperInterface;
}
}
public class SqlSessionTemplate implements SqlSession, DisposableBean {
public <T> T getMapper(Class<T> type) {
// 最终去sqlSessionFactory.Configuration.mapperRegistry去获取我们的Mapper对象
return getConfiguration().getMapper(type, this);
}
}