MybatisPlus整合Flowable出现的坑

2023-10-31

MybatisPlus整合Flowable出现的坑

- 摘要:现在在项目中使用的MybatisPlus,最近研究了一下流程框架Flowable,看了很多技术文档博客,打算直接整合进去,先记录一下遇到的问题:
- 问题:
Description:

file [D:\project\carshow-server\server-flowable\flowable-admin\target\classes\com\carshow\flowable\mapper\IFlowableCommentMapper.class] required a single bean, but 2 were found:
	- sqlSessionFactory: defined by method 'sqlSessionFactory' in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]
	- modelerSqlSessionFactory: defined by method 'modelerSqlSessionFactory' in class path resource [org/flowable/ui/modeler/conf/ModelerDatabaseConfiguration.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
- 原因:整合的bean冲突,spring找到了两个
- 查看两个类源码找到对应的bean:

MybatisPlus: MybatisPlusAutoConfiguration.class

在这里插入图片描述
Flowable:ModelerDatabaseConfiguration.class

在这里插入图片描述

- 注解解释:

@ConditionalOnMissingBean:它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果有注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常,以此来告诉开发人员。

所以问题就来了,找到了这两个bean冲突,接下来如何进行解决呢,查看了一下源码并查阅了其他大佬的技术博客,记录一下

1. 环境:Flowable6.6
2. 解决:
  • 重写mybatis-plus 自动配置类(由于 flowable-modeler 引入时候,会初始化 mybatis的Template和SqlFactory,这导致 mybatis-plus 本身的autoconfig 无法生效,所以需要重写),从源码中拆写代码:
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
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.springframework.context.ApplicationContext;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.List;

/**
 * @author xw
 * @description 重写mybatis-plus 自动配置类
 * @date 2022/1/7 14:06
 */
public class AbstractMybatisPlusConfiguration {

    protected SqlSessionFactory getSqlSessionFactory(
            DataSource dataSource,
            MybatisPlusProperties properties,
            ResourceLoader resourceLoader,
            Interceptor[] interceptors,
            DatabaseIdProvider databaseIdProvider,
            ApplicationContext applicationContext
    ) throws Exception {
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(properties.getConfigLocation())) {
            factory.setConfigLocation(resourceLoader.getResource(properties.getConfigLocation()));
        }
        applyConfiguration(factory, properties);
        if (properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(properties.getConfigurationProperties());
        }
        if (!ObjectUtils.isEmpty(interceptors)) {
            factory.setPlugins(interceptors);
        }
        if (databaseIdProvider != null) {
            factory.setDatabaseIdProvider(databaseIdProvider);
        }
        if (StringUtils.hasLength(properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(properties.getTypeAliasesPackage());
        }
        // TODO 自定义枚举包
        if (StringUtils.hasLength(properties.getTypeEnumsPackage())) {
            factory.setTypeEnumsPackage(properties.getTypeEnumsPackage());
        }
        if (properties.getTypeAliasesSuperType() != null) {
            factory.setTypeAliasesSuperType(properties.getTypeAliasesSuperType());
        }
        if (StringUtils.hasLength(properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(properties.resolveMapperLocations())) {
            factory.setMapperLocations(properties.resolveMapperLocations());
        }
        // TODO 此处必为非 NULL
        GlobalConfig globalConfig = properties.getGlobalConfig();
        //注入填充器
        if (applicationContext.getBeanNamesForType(MetaObjectHandler.class,
                false, false).length > 0) {
            MetaObjectHandler metaObjectHandler = applicationContext.getBean(MetaObjectHandler.class);
            globalConfig.setMetaObjectHandler(metaObjectHandler);
        }
        //注入主键生成器
        if (applicationContext.getBeanNamesForType(IKeyGenerator.class, false,
                false).length > 0) {
            IKeyGenerator keyGenerator = applicationContext.getBean(IKeyGenerator.class);
            globalConfig.getDbConfig().setKeyGenerators((List<IKeyGenerator>) keyGenerator);
        }
        //注入sql注入器
        if (applicationContext.getBeanNamesForType(ISqlInjector.class, false,
                false).length > 0) {
            ISqlInjector iSqlInjector = applicationContext.getBean(ISqlInjector.class);
            globalConfig.setSqlInjector(iSqlInjector);
        }
        factory.setGlobalConfig(globalConfig);
        return factory.getObject();
    }

    private void applyConfiguration(MybatisSqlSessionFactoryBean factory, MybatisPlusProperties properties) {
        MybatisConfiguration configuration = properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(properties.getConfigLocation())) {
            configuration = new MybatisConfiguration();
        }
//        if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
//            for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
//                customizer.customize(configuration);
//            }
//        }
        factory.setConfiguration(configuration);
    }

    public SqlSessionTemplate getSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, MybatisPlusProperties properties) {
        ExecutorType executorType = properties.getExecutorType();
        if (executorType != null) {
            return new SqlSessionTemplate(sqlSessionFactory, executorType);
        } else {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }
}

  • 继承重写的配置类
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;

import javax.sql.DataSource;

/**
 * @author xw
 * @description
 * @date 2022/1/7 16:24
 */
@MapperScan(
        sqlSessionTemplateRef = "mySqlSessionTemplate",
        sqlSessionFactoryRef = "mySqlSessionFactory"
)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@Configuration
public class MybatisPlusConfiguration extends AbstractMybatisPlusConfiguration {

    @Bean(name = "mySqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource,
                                                   MybatisPlusProperties properties,
                                                   ResourceLoader resourceLoader,
                                                   ApplicationContext applicationContext) throws Exception {
        return getSqlSessionFactory(dataSource,
                properties,
                resourceLoader,
                null,
                null,
                applicationContext);
    }

    @Bean(name = "mySqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(MybatisPlusProperties properties,
                                                 @Qualifier("mySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return getSqlSessionTemplate(sqlSessionFactory, properties);
    }
}

  • 重写 flowable-modeler 中 ModelerDatabaseConfiguration,用 @Primary 指定框架内部的mybatis 作为默认的
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.ui.common.service.exception.InternalServerErrorException;
import org.flowable.ui.modeler.properties.FlowableModelerAppProperties;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author xw
 * @description 重写 flowable-modeler 中 ModelerDatabaseConfiguration
 * @date 2022/1/7 16:31
 */

@Configuration
@Slf4j
public class DatabaseConfiguration {

    protected static final String LIQUIBASE_CHANGELOG_PREFIX = "ACT_DE_";

    @Autowired
    protected FlowableModelerAppProperties modelerAppProperties;

    @Autowired
    protected ResourceLoader resourceLoader;

    protected static Properties databaseTypeMappings = getDefaultDatabaseTypeMappings();

    public static final String DATABASE_TYPE_H2 = "h2";
    public static final String DATABASE_TYPE_HSQL = "hsql";
    public static final String DATABASE_TYPE_MYSQL = "mysql";
    public static final String DATABASE_TYPE_ORACLE = "oracle";
    public static final String DATABASE_TYPE_POSTGRES = "postgres";
    public static final String DATABASE_TYPE_MSSQL = "mssql";
    public static final String DATABASE_TYPE_DB2 = "db2";

    public static Properties getDefaultDatabaseTypeMappings() {
        Properties databaseTypeMappings = new Properties();
        databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2);
        databaseTypeMappings.setProperty("HSQL Database Engine", DATABASE_TYPE_HSQL);
        databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL);
        databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE);
        databaseTypeMappings.setProperty("PostgreSQL", DATABASE_TYPE_POSTGRES);
        databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL);
        databaseTypeMappings.setProperty(DATABASE_TYPE_DB2, DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/NT", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/NT64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2 UDP", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUX", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUX390", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUXX8664", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUXZ64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUXPPC64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/400 SQL", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/6000", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2 UDB iSeries", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/AIX64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/HPUX", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/HP64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/SUN", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/SUN64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/PTX", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/2", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2);
        return databaseTypeMappings;
    }

    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        String databaseType = initDatabaseType(dataSource);
        if (databaseType == null) {
            throw new FlowableException("couldn't deduct database type");
        }

        try {
            Properties properties = new Properties();
            properties.put("prefix", modelerAppProperties.getDataSourcePrefix());
            properties.put("blobType", "BLOB");
            properties.put("boolValue", "TRUE");

            properties.load(this.getClass().getClassLoader().getResourceAsStream("org/flowable/db/properties/" + databaseType + ".properties"));

            sqlSessionFactoryBean.setConfigurationProperties(properties);
            sqlSessionFactoryBean
                    .setMapperLocations(ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources("classpath:/META-INF/modeler-mybatis-mappings/*.xml"));
            sqlSessionFactoryBean.afterPropertiesSet();
            return sqlSessionFactoryBean.getObject();
        } catch (Exception e) {
            throw new FlowableException("Could not create sqlSessionFactory", e);
        }

    }

    @Primary
    @Bean(destroyMethod = "clearCache") // destroyMethod: see https://github.com/mybatis/old-google-code-issues/issues/778
    public SqlSessionTemplate SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    public Liquibase liquibase(DataSource dataSource) {
        log.info("Configuring Liquibase");

        Liquibase liquibase = null;
        try {
            DatabaseConnection connection = new JdbcConnection(dataSource.getConnection());
            Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);
            database.setDatabaseChangeLogTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogTableName());
            database.setDatabaseChangeLogLockTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogLockTableName());

            liquibase = new Liquibase("META-INF/liquibase/flowable-modeler-app-db-changelog.xml", new ClassLoaderResourceAccessor(), database);
            liquibase.update("flowable");
            return liquibase;

        } catch (Exception e) {
            throw new InternalServerErrorException("Error creating liquibase database", e);
        } finally {
            closeDatabase(liquibase);
        }
    }

    protected String initDatabaseType(DataSource dataSource) {
        String databaseType = null;
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            DatabaseMetaData databaseMetaData = connection.getMetaData();
            String databaseProductName = databaseMetaData.getDatabaseProductName();
            log.info("database product name: '{}'", databaseProductName);
            databaseType = databaseTypeMappings.getProperty(databaseProductName);
            if (databaseType == null) {
                throw new FlowableException("couldn't deduct database type from database product name '" + databaseProductName + "'");
            }
            log.info("using database type: {}", databaseType);

        } catch (SQLException e) {
            log.error("Exception while initializing Database connection", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                log.error("Exception while closing the Database connection", e);
            }
        }

        return databaseType;
    }

    private void closeDatabase(Liquibase liquibase) {
        if (liquibase != null) {
            Database database = liquibase.getDatabase();
            if (database != null) {
                try {
                    database.close();
                } catch (DatabaseException e) {
                    log.warn("Error closing database", e);
                }
            }
        }
    }

}

  • 以上关于Mybatis-Plus整合Flowable的坑就处理完啦,重启ok!
- 之后也会找个时间记录SpringCloud微服务中整合Flowable服务的流程,加油!

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MybatisPlus整合Flowable出现的坑 的相关文章

随机推荐

  • 获得KeyStore的sha1值

    keytool list v keystore E geniatech ham project keystore
  • rabbitmq取消自动重连_rabbitmq客户端自动重连

    编程rookie 如有错误请指出 253065903 qq com RabbitMQ Node js 客户端 AMQP 0 9 1 V0 5 2 自动重连 重启策略 开始找解决方案 通过查看AMQP的源码 发现没有reconnect的选项
  • linux下使用bower时提示bower ESUDO Cannot be run with sudo解决办法

    今天准备在使用bower安装一些东西的时候 废了老半天劲 因为需要node环境以及bower平台 安装不顺利 通过百度 最解决了这些问题 在执行bower命令的时候 总是会报错 原来需要在命令后添加 allow root 选项 bower
  • 星星之火-36:LTE载波载波的间隔是15K, 载波波的带宽是多少? 15K还是30K?

    先给个结论 在LTE中 单个小区最大的频谱带宽为20M 每个子载波的间隔为15K 带宽为30K 一共可以分为1200个子载波 那这个数据是怎么来得呢 15K子载波间隔的由来 如果子载波的带宽30K 那么按照频分复用FDM的规则 频谱利用率最
  • Java 类、对象和方法

    Java 类 对象和方法 类的基础知识 如何创建对象 引用变量和赋值 方法 返回值 实参与形参 构造函数 垃圾回收机制 this关键字 类的基础知识 类是定义对象形式的模板 指定了数据以及操作数据的代码 Java中使用类的规范来构造对象 而
  • Qt - 富文本(富文本编程-语法高亮)

    富文本 QTextEdit支持富文本处理 即文档中可使用多种格式 如文字 图片 表格等 与纯文本PlainText相对而言 windows的记事本就是纯文本编辑器 word就是富文本编辑器 文档的光标主要基于QTextCursor类 文档的
  • 贵州大学计算机系2020年录取分数线,贵州大学2020年高考录取分数线汇总

    作为贵州省最好的大学 贵州大学一直是省内考生报考的热门学校 2020年 学校在贵州省招生类别有国家专项 地方专项 高校专项 本科一批 本科二批 艺术体育类 少数民族预科班等 由于本科二批 艺术体育类和少数民族预科班的录取分数线已经在动态里做
  • HttpServletRequestWrapper处理request数据流多次读取问题

    问题 要实现一个spring拦截器需要读取request数据流 但是request数据流只能读取一次 需要自己实现HttpServletRequestWrapper对数据流包装 实现如下 public class ReadHttpServl
  • ov9650摄像头驱动之——linux内核v4l2架构分析2

    NO 2 Camera解码器 控制器 1 根据camera控制器的描述 图像传输有两个DMA通道 我们用的是C通道 所以先将DMA内存初始化 因为在V4L2操作中有把VIDIOC REQBUFS中分配的数据缓存转换成物理地址的操作 所以DM
  • ctfshow

    第三题 1 抓包 2 发送到repeater 获得flag 第四题 robots txt是一种存放于网站根目录下的ASCII编码的文本文件 它通常告诉网络搜索引擎的漫游器 又称网络蜘蛛 此网站中的哪些内容是不能被搜索引擎的漫游器获取的 哪些
  • Linux(centos7.9)常用命令大全及基础知识

    linux中数组的索引从0开始 其他默认从1开始 例如没有第0列 从第1列开始 在Unix中一切 包括网络套接口 都是文件 在命令行中 无论几个空格 都当成一个空格看待 在linux中 在命令行中通过执行命令的方式来改变系统或软件配置时 效
  • mysql数据库管理工具 h_几款桌面MYSQL管理工具

    1 Navicat Navicat是一个强大的MySQL数据库管理和开发工具 Navicat导航为专业开发者提供了一套强大的足够尖端的工具 但它对于新用户仍然 是易于 学习 Navicat 使用了极好的图形用户界面 GUI 可以让你用一种安
  • 数据预处理——数据无量纲化(归一化、标准化)

    文章目录 1 数据归一化 1 1 数据归一化定义 1 2 MinMaxScaler 归一化 1 3 MinMaxScaler 使用样例 2 数据标准化 2 1 数据标准化定义 2 2 StandardScaler 标准化 2 3 Stand
  • python如何求列表的平均值_python如何求列表平均值?

    推荐教程 python视频教程 python如何求列表平均值 python函数求列表平均值的方法 用法 mean matrix axis 0 其中matrix为一个矩阵 axis为参数 以m n矩阵举例 axis不设置值 对 m n 个数求
  • mysql基础命令

    1 常用命令 1 create database db name 创建数据库 2 show databases 显示所有的数据库 3 drop database db name 删除数据库 4 show tables 显示数据表 5 des
  • 三菱j4伺服中文说明书_三菱伺服抱闸伺服的使用方法

    刹车原理 伺服电机的刹车抱闸和普通的电磁抱闸原理是一样的 靠电磁线圈产生磁场吸力 克服机械刹车片的弹簧制动力矩 驱动机械刹车片的分开 释放电机轴 一般三菱伺服的刹车都是直流24V电源 他的刹车是不分正负极 很多初次使用的工控人员都会纠结这个
  • 网站设计之常见简单实用的JavaScript特效总结(上篇)

    这篇主要是总结JavaScript常见简单实用的特效 主要从代码量短 简单实用几个方面进行叙述 其中特效包括 1 鼠标悬停图片切换查看器 2 鼠标移动图片放大 3 鼠标移动切换内容 4 贵财下拉菜单案例 5 JS图片放大镜功能 类似淘宝 6
  • 【无标题】文件查找、运行项目(网站)HTML5(H5)、压缩---解压缩

    一 登录系统 用户名 root 密钥对 安全组 云服务器 来源 0 0 0 0 0 端口 ALL TCP 80 策略 允许 物理服务器 虚拟机 systemctl stop firewalld 关闭防火墙 setenforce 0 关闭se
  • ethers.js 应用(助记词、地址、私钥)

    1 创建助记词 const ethers require ethers let wallet ethers Wallet createRandom let mnemonic wallet mnemonic console log mnemo
  • MybatisPlus整合Flowable出现的坑

    MybatisPlus整合Flowable出现的坑 摘要 现在在项目中使用的MybatisPlus 最近研究了一下流程框架Flowable 看了很多技术文档博客 打算直接整合进去 先记录一下遇到的问题 问题 Description file