写点什么

实践丨 SpringBoot 整合 Mybatis-Plus 项目存在 Mapper 时报错

  • 2022 年 3 月 25 日
  • 本文字数:5160 字

    阅读完需:约 17 分钟

本文分享自华为云社区《SpringBoot整合MybatisPlus项目存在Mapper时运行报错的问题分析与修复》,作者:攻城狮 Chova 。

异常信息

  • 在 SpringBoot 运行测试 Mybatis-Plus 测试的时候报错:

rg.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.oxford.test.ApplicationTests':
复制代码

原因

  • 自定义的 mapper 文件不受 Spring 管理所以不会注入到 Spring 容器中

  • mybatis-config 中只是会为对应的 mapper 创建代理类

  • 想真正包装成 bean, 注入到 spring 容器中,需要使用到 AutoConfiguredMapperScannerRegistrar 它会根据扫描 @Mapper 注释或是 @MapperScan 指定的包下的接口,将其注册为 bean


  • AutoConfiguredMapperScannerRegistrar:


//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//
package com.baomidou.mybatisplus.spring.boot.starter;
import com.baomidou.mybatisplus.MybatisConfiguration;import com.baomidou.mybatisplus.MybatisXMLLanguageDriver;import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;import java.util.Iterator;import java.util.List;import javax.annotation.PostConstruct;import javax.sql.DataSource;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.logging.Log;import org.apache.ibatis.logging.LogFactory;import org.apache.ibatis.mapping.DatabaseIdProvider;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.session.ExecutorType;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionTemplate;import org.mybatis.spring.mapper.ClassPathMapperScanner;import org.mybatis.spring.mapper.MapperFactoryBean;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.ObjectProvider;import org.springframework.beans.factory.support.BeanDefinitionRegistry;import org.springframework.boot.autoconfigure.AutoConfigurationPackages;import org.springframework.boot.autoconfigure.AutoConfigureAfter;import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.ResourceLoaderAware;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;import org.springframework.core.io.Resource;import org.springframework.core.io.ResourceLoader;import org.springframework.core.type.AnnotationMetadata;import org.springframework.util.Assert;import org.springframework.util.CollectionUtils;import org.springframework.util.ObjectUtils;import org.springframework.util.StringUtils;
@Configuration@ConditionalOnClass({SqlSessionFactory.class, MybatisSqlSessionFactoryBean.class})@ConditionalOnBean({DataSource.class})@EnableConfigurationProperties({MybatisPlusProperties.class})@AutoConfigureAfter({DataSourceAutoConfiguration.class})public class MybatisPlusAutoConfiguration { private static final Log logger = LogFactory.getLog(MybatisPlusAutoConfiguration.class); private final MybatisPlusProperties properties; private final Interceptor[] interceptors; private final ResourceLoader resourceLoader; private final DatabaseIdProvider databaseIdProvider; private final List<ConfigurationCustomizer> configurationCustomizers;
public MybatisPlusAutoConfiguration(MybatisPlusProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) { this.properties = properties; this.interceptors = (Interceptor[])interceptorsProvider.getIfAvailable(); this.resourceLoader = resourceLoader; this.databaseIdProvider = (DatabaseIdProvider)databaseIdProvider.getIfAvailable(); this.configurationCustomizers = (List)configurationCustomizersProvider.getIfAvailable(); }
@PostConstruct public void checkConfigFileExists() { if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); Assert.state(resource.exists(), "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)"); }
}
@Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setVfs(SpringBootVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) { factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); }
MybatisConfiguration configuration = this.properties.getConfiguration(); if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { configuration = new MybatisConfiguration(); }
if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { Iterator i$ = this.configurationCustomizers.iterator();
while(i$.hasNext()) { ConfigurationCustomizer customizer = (ConfigurationCustomizer)i$.next(); customizer.customize(configuration); } }
configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class); factory.setConfiguration(configuration); if (this.properties.getConfigurationProperties() != null) { factory.setConfigurationProperties(this.properties.getConfigurationProperties()); }
if (!ObjectUtils.isEmpty(this.interceptors)) { factory.setPlugins(this.interceptors); }
if (this.databaseIdProvider != null) { factory.setDatabaseIdProvider(this.databaseIdProvider); }
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); }
if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); }
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); }
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { factory.setMapperLocations(this.properties.resolveMapperLocations()); }
if (!ObjectUtils.isEmpty(this.properties.getGlobalConfig())) { factory.setGlobalConfig(this.properties.getGlobalConfig().convertGlobalConfiguration()); }
return factory.getObject(); }
@Bean @ConditionalOnMissingBean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { ExecutorType executorType = this.properties.getExecutorType(); return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory); }
@Configuration @Import({MybatisPlusAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class}) @ConditionalOnMissingBean({MapperFactoryBean.class}) public static class MapperScannerRegistrarNotFoundConfiguration { public MapperScannerRegistrarNotFoundConfiguration() { }
@PostConstruct public void afterPropertiesSet() { MybatisPlusAutoConfiguration.logger.debug("No " + MapperFactoryBean.class.getName() + " found."); } }
public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware { private BeanFactory beanFactory; private ResourceLoader resourceLoader;
public AutoConfiguredMapperScannerRegistrar() { }
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { MybatisPlusAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper"); ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
try { if (this.resourceLoader != null) { scanner.setResourceLoader(this.resourceLoader); }
List<String> packages = AutoConfigurationPackages.get(this.beanFactory); if (MybatisPlusAutoConfiguration.logger.isDebugEnabled()) { Iterator i$ = packages.iterator();
while(i$.hasNext()) { String pkg = (String)i$.next(); MybatisPlusAutoConfiguration.logger.debug("Using auto-configuration base package '" + pkg + "'"); } }
scanner.setAnnotationClass(Mapper.class); scanner.registerFilters(); scanner.doScan(StringUtils.toStringArray(packages)); } catch (IllegalStateException var7) { MybatisPlusAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled." + var7); }
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; }
public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } }}
复制代码

解决办法

@Mapper

  • mapper 文件的类上添加 @Mapper 注解

@MapperScan

  • 在主类上添加 @MapperScan 注解,指定 mapper 的扫描范围,注意值为 mapper 文件所在的包名

@MapperScan("com.oxford.mapper")
复制代码


点击关注,第一时间了解华为云新鲜技术~​

发布于: 刚刚阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
实践丨SpringBoot整合Mybatis-Plus项目存在Mapper时报错_spring_华为云开发者社区_InfoQ写作平台