【Mybatis-源码解析】11 启动过程中,Mapper

启动过程中,Mapper接口的扫描与代理注册

整体流程

简易流程图

整体流程创建扫描器实例扫描器根据配置注册过滤器扫描器进行扫描扫描后获取bean定义交给Spring进行加载spring通过MapperFactoryBean获取到Mapper的代理对象结束

文本概括

  1. 创建扫描器实例
    • 如何使用的是@MapperScan,@MapperScan中配置了@Import(MapperScannerRegistrar.class)注解 会使MapperScannerRegistrar类在启动时自动加载 (待-见spring学习)
      • MapperScannerRegistrar 并加载 registerBeanDefinitions 方法
        • 创建扫描器实例
          • 设置resourceLoader属性(资源加载器)
          • 设置Annotation属性(被修饰的注解)
          • 设置markerInterface属性(继承的父类)
          • 设置ameGenerator属性(名字生成器)
          • 设置factoryBean属性 (工厂bean对象)
          • 设置SqlSessionTemplateBeanName属性 (指定使用的SqlSessionTemplate、通常多个数据源使用)
          • 设置basePackages属性 (要扫描的包)
    • 如果在mapper接口上配置@Mapper注解后,MybatisAutoConfiguration中的内部类AutoConfiguredMapperScannerRegistrar
      • 执行registerBeanDefinitions方法
        • 创建扫描器实例
          • 设置resourceLoader属性(资源加载器)
          • 设置Annotation属性(被修饰的注解)设置值为Mapper.class
  2. 扫描器注册过滤器
    • 判断是否设置了Annotation类型,如果设置了添加指定注解类型的过滤器
    • 判断是否设置了markerInterface属性,如果设置了添加指定父类的过滤器
    • 如果以上属性没有被设置,添加默认的过滤器(直接返回true - 不过滤)
    • 添加 package-info.java 过滤器
  3. 扫描器进行扫描
    • 将包路径交给父类扫描(org.springframework.context.annotation.ClassPathBeanDefinitionScanner)扫描
    • 对扫描后得到的bean定义持有者们进行遍历
      • 获取bean定义
      • 设置bean定义的 原类型和bean类(mapperFactoryBean)
      • bean定义中添加属性 addToConfig
      • 如果设置了sqlSessionTemplate 或者 设置了sqlSessionFactory的话,将bean定义自定注入类型设置为 AUTOWIRE_BY_TYPE (根据类型)
  4. bean定义修改好后,将bean定义交给 springbean的注册实例方法 进行实例化
    • 最终调用org.mybatis.spring.mapper.MapperFactoryBean#getObject获取mapper的代理实例
      • 调用SqlSession获取Mapper实例
      • 在SqlSession中获取configuration对象,通过configuration获取Mapper实例
      • 在configuration中获取mapperRegistry对象,在mapperRegistry中获取Mapper实例
      • 通过mapperRegistry中的knownMappers(Key(接口class),value该接口的代理工厂对象)获取到代理工厂对象 (在启动时解析mapper.xml中sql的时候存储的 方法 -> xmlMapperBuilder.parse())
      • 通过代理工厂对象获取代理实例
      • 通过SqlSession创建代理对象
      • 将代理对象交给代理,代理的类为mapper接口

springboot启动类配置@MapperScan

源码解析(MapperScannerRegistrar.registerBeanDefinitions)

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
scss复制代码  @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

// 获取MapperScan对象
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
// 通过bean注册表获取 mapper类路径扫描器
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

// 设置 资源加载器
if (resourceLoader != null) {
scanner.setResourceLoader(resourceLoader);
}

// 在MapperScan中获取annotationClass属性 如果不为Annotation类型 扫描器中设置 AnnotationClass
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}

// 在MapperScan中获取markerInterface属性 如果不为Class类型 扫描器中配置markerInterface
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}

// 在MapperScan中获取nameGenerator属性 如果不为BeanNameGenerator类型 扫描器中配置generatorClass
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
}

// 在MapperScan中获取factoryBean属性 如果不为MapperFactoryBean类型 扫描器中配置mapperFactoryBeanClass
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
}

// 扫描器中配置SqlSessionTemplateBeanName 和 SqlSessionFactoryBeanName
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));

// 设置要扫描的包
List<String> basePackages = new ArrayList<String>();
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}

// 扫描器注册过滤器
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}

接口上配置@mapper注解

在MybatisAutoConfiguration中有一个内部类:AutoConfiguredMapperScannerRegistrar,内部类AutoConfiguredMapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,在spring项目启动时会执行registerBeanDefinitions方法

源码解析(AutoConfiguredMapperScannerRegistrar#registerBeanDefinitions)

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
typescript复制代码    @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

// 通过bean注册表获取 mapper类路径扫描器
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

try {
// 在类扫描器中中 设置 resourceLoader
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
}

// 会获取到启动类所在的包,作为扫描包的根路径
List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
if (logger.isDebugEnabled()) {
for (String pkg : packages) {
logger.debug("Using auto-configuration base package '{}'", pkg);
}
}

// 设置要扫描的注解为 Mapper
scanner.setAnnotationClass(Mapper.class);
// 注册过滤器
scanner.registerFilters();
// 进行扫描
scanner.doScan(StringUtils.toStringArray(packages));

} catch (IllegalStateException ex) {
logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
}
}

通用方法

源码解析(registerFilters)

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
java复制代码public void registerFilters() {
// 是否全接口注入标记
boolean acceptAllInterfaces = true;

// 如果配置了 annotationClass,新增一个注解过滤器,并且设置不全注入
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}

// 如果配置了 markerInterface,新增一个父类接口过滤器,并且设置不全注入
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}

// 如果全接口注入
if (acceptAllInterfaces) {
// 新增一个默认的过滤器,比较永远返回true
addIncludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
}

// 排除 package-info.java 类
addExcludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
}
});
}

源码解析(doScan)

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
kotlin复制代码  @Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 使用spring的扫描器获取到 bean定义的持有者
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

// 如果bean定义为空,打印警告日志 否则 处理bean的持有者定义
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}

return beanDefinitions;
}


private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
// 声明一个 GenericBeanDefinition 实例
GenericBeanDefinition definition;

// 循环所有的bean定义持有者
for (BeanDefinitionHolder holder : beanDefinitions) {
// 获取持有者的bean定义
definition = (GenericBeanDefinition) holder.getBeanDefinition();


// 设置bean定义的 原类型和bean类(mapperFactoryBean)
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
definition.setBeanClass(this.mapperFactoryBean.getClass());

// bean定义中添加属性 addToConfig
definition.getPropertyValues().add("addToConfig", this.addToConfig);

// 声明 是否有使用的bean工厂标识 默认 没有,当有设置SessionFactoryBeanName或者当前sqlSessionFactory不为空是 添加属性sqlSessionFactory 并将标识改为true
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;
}

// 如果设置了 SessionTemplateBeanName 或者 当前类有 sqlSessionTemplate 时添加属性 sqlSessionTemplate 并将 并将 是否有使用的bean工厂标识 改为true
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}

// 如果 有使用的bean工厂标识 设置自动装配模式为 根据类型装配
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}

获取代理BEAN

源码解析(MapperFactoryBean#getObject)

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
typescript复制代码  @Override
public T getObject() throws Exception {
// 通过SqlSession获取Mapper实例
return getSqlSession().getMapper(this.mapperInterface);
}


@Override
public <T> T getMapper(Class<T> type) {
// 通过configuration获取Mapper实例
return configuration.<T>getMapper(type, this);
}

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 调用mapper注册器获取mapper实例
return mapperRegistry.getMapper(type, sqlSession);
}

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// knownMappers 为mybatis启动时扫描mapper接口,存放到mapperRegistry的knownMappers的mapperProxyFactory(代理工厂对象)
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);

// 如果代理工厂对象为空 标识该接口没有被注册
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}


try {
/**
* 通过代理工厂获取到代理对象实例
*
* 1. 根据sqlSession创建MapperProxy代理类(设置sqlSession、mapperInterface、methodCache属性)
* 2. 将MapperProxy交由代理(Proxy.newProxyInstance)代理接口为mapperInterface
*/
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}

文章链接

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%