基于Spring整合mybatis的mapper生成过程
作者:asLightYouAre
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一份
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。