SpringBoot整合MybatisPlus项目存在Mapper时运行报错的问题分析与修复-阿里云开发者社区

开发者社区> 攻城狮Chova> 正文

SpringBoot整合MybatisPlus项目存在Mapper时运行报错的问题分析与修复

简介: 本篇文章记录了在使用SpringBoot项目,集成MyBatisPlus框架后。自定义Mapper文件运行时发生报错的问题的分析与修复的过程。由于自定义的Mapper文件不受Spring的管理,从而不会将自定义的Mapper文件注册到Spring容器中,从而导致项目运行报错。在分析解决问题的过程中,将这个问题记录下来,帮助后来的人避免相关的问题。
+关注继续查看

异常信息

  • 在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")

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
spring-boot项目整合redis
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。 Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
1378 0
深入JavaWeb技术世界15:通过项目逐步深入了解Mybatis(二)
本文出自我的公众号:程序员江湖。 满满干货,关注就送。 转自http://www.54tianzhisheng.cn/2017/06/13 Mybatis 解决 jdbc 编程的问题 1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
1166 0
spring4+hibernate4+struts2项目整合的步骤及注意事项
  首先,在整合框架之前,我们需要知道Spring框架在普通Java project和Web project中是略有不同的.   这个不同地方就在于创建IOC容器实例的方式不同,在普通java工程中,可以在main方法中直接创建,可是web工程就不一样了,在Web项目工程中应该在服务器加载时就创建IOC容器.
767 0
好好编程-物流项目06【Spring整合】
上篇文章中我们整合了Dao层,本篇文章将Spring整合进来。 Spring整合
10 0
超大坑!springboot + vue + element-ui,运行前端项目报these dependencies were not found的问题
These dependencies were not found: * babel-runtime/core-js/json/stringify in ./src/mock/modules/sys-menu.
7936 0
Spring Boot项目利用MyBatis Generator进行数据层代码自动生成
概 述 MyBatis Generator (简称 MBG) 是一个用于 MyBatis和 iBATIS的代码生成器。它可以为 MyBatis的所有版本以及 2.2.0之后的 iBATIS版本自动生成 ORM层代码,典型地包括我们日常需要手写的 POJO、mapper xml 以及 mapper 接口等。
1838 0
+关注
攻城狮Chova
一位有自我修养的攻城狮。 2006年《时代》周刊年度人物, 2008年感动中国组委会特别奖获得者。 专注分享技术干货,面试经验和攻城狮故事~ 欢迎点赞关注支持,是我持续进步的动力!
77
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载