1. 程式人生 > 其它 >實踐丨SpringBoot整合Mybatis-Plus專案存在Mapper時報錯

實踐丨SpringBoot整合Mybatis-Plus專案存在Mapper時報錯

摘要:在SpringBoot執行測試Mybatis-Plus測試的時候報錯的問題分析與修復

本文分享自華為雲社群《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")

 

點選關注,第一時間瞭解華為雲新鮮技術~