基于Spring整合mybatis的mapper生成过程

 更新时间:2023年03月07日 15:09:16   作者:asLightYouAre  
这篇文章主要介绍了Spring整合mybatis的mapper生成过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Spring整合mybatis的mapper生成过程

mapperScannerConfigurer实现了BeandifinitionRegistryPostProcessor

后置处理beanFactory时会调用其postProcessBeanDefinitionRegistry

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }
 
    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);
    scanner.registerFilters();
//扫描包集合,注册mapper的beandifinition
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

ClassPathMapperScanner#doScan

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
 
    if (beanDefinitions.isEmpty()) {
      LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
    } else {
//会对bean信息进行一些更改和添加,如设置propertyValues,向其中添加sqlsessionFactory等属性信息等
      processBeanDefinitions(beanDefinitions);
    }
 
    return beanDefinitions;
  }

ClassPathBeanDefinitionScanner#doScan

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
//遍历集合扫描包,获取包下的可用的mapper信息
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

 

如上在进行包扫描时,会调用ClassPathBeanDefinitionScanner#doScan,进行beanDefinition的扫描和注册

执行完后调用ClassPathMapperScanner#processBeanDefinitions

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
//有省略部分
       
    //这里有遍历所有mapper
//将所有mapper的beanClass改为了mapperFactoryBean,最后生成的bean也是该类型的,只有在用到的
//时候才会调用getObject生成mapper
      definition.setBeanClass(this.mapperFactoryBeanClass);
//接下来是添加一些MapperFactoryBean的属性信息到beandefinition里,在生成实例的时候,会根据
//此处传入的值来进行具体设置,如sqlsessionFactory
      definition.getPropertyValues().add("addToConfig", this.addToConfig);
 
      
      if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
        definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
      
      } else if (this.sqlSessionFactory != null) {
        definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
        
      }
 
      if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
        
        definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
        
      } else if (this.sqlSessionTemplate != null) {
        
        definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
        
      }
  }

确定了所有的mapper的beanDefinition为MapperFactoryBean类型后,

确定在生成的bean皆为MapperFactoryBean,在getBean时会调用MapperFactoryBean#getObject

mapperInterface是在MapperFactoryBean创建时,会调用有参构造创建实例,值是创建是

 构造方法参数的获取从mdb中

创建除了传入mapperInterface,还会在设置属性值时调用MapperFactoryBean的父类SqlSessionDaoSupport#setSqFactory 将mdb中的sqlsessionfactory传入其中

mdb的sqlsessionFactory信息来历

查看方法栈调用,可以看到在开始填充属性时会去mdb中判断是否有propertyValue,如果有就返回,这就是之前扫描mapper后ClassPathMapperScanner#processBeanDefinitions对mdb的一些设置

在创造service时,如果有@Autowire 注入mapper,在createBean时会调用getObject

mdb只有一份,可得sqlsessionfactory即只有一份,sqlsessionTemplate一个mapper一份

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java中transient关键字的作用解析

    java中transient关键字的作用解析

    这篇文章主要介绍了java中transient关键字的作用解析,日常业务中,为了安全起见,有些敏感信息我们不希望在网络间被传输可以使用transient对字段进行修饰,不进行序列化,则返回获取到的字段为null,需要的朋友可以参考下
    2023-11-11
  • SpringBoot项目引入MCP的实现示例

    SpringBoot项目引入MCP的实现示例

    本文主要介绍了SpringBoot项目引入MCP的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04
  • 详解使用spring aop实现业务层mysql 读写分离

    详解使用spring aop实现业务层mysql 读写分离

    本篇文章主要介绍了使用spring aop实现业务层mysql 读写分离,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • 使用递归算法结合数据库解析成Java树形结构的代码解析

    使用递归算法结合数据库解析成Java树形结构的代码解析

    这篇文章主要介绍了使用递归算法结合数据库解析成Java树形结构的代码解析的相关资料,需要的朋友可以参考下
    2017-09-09
  • Java 实战练习之网上电商项目的实现

    Java 实战练习之网上电商项目的实现

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+vue+Springboot+ssm+mysql+maven+redis实现一个网上电商项目,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • 基于mybatis like %%的问题

    基于mybatis like %%的问题

    这篇文章主要介绍了mybatis like %%的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Java 代码本地设置Hadoop用户名密码的方法

    Java 代码本地设置Hadoop用户名密码的方法

    在Hadoop环境中,通常使用Kerberos进行身份验证,这篇文章主要介绍了Java 代码本地设置Hadoop用户名密码的方法,需要的朋友可以参考下
    2024-08-08
  • Java中finally关键字对返回值的影响详解

    Java中finally关键字对返回值的影响详解

    这篇文章主要介绍了Java中finally关键字对返回值的影响详解,执行完try catch里面内容准备return时,如果还有finally需要执行这是编译器会为我们增加一个全局变量去暂存return 的值,等到finally执行完成去return这个全局变量,需要的朋友可以参考下
    2024-01-01
  • SpringCloud注册中心之consul详细讲解使用方法

    SpringCloud注册中心之consul详细讲解使用方法

    Consul是一款由HashiCorp公司开源的,用于服务治理的软件,Spring Cloud Consul对其进行了封装,这篇文章主要介绍了springcloud组件consul服务治理,需要的朋友可以参考下
    2022-11-11
  • Java8新特性Stream流详解

    Java8新特性Stream流详解

    Java8 Stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合进行链状流式的操作,本文就将带着你如何使用 Java 8 不同类型的 Stream 操作,同时还将了解流的处理顺序,以及不同顺序的流操作是如何影响运行时性能的
    2023-07-07

最新评论