MybatisPlus整合Flowable出现的坑及解决

作者:夕夕夕兮 时间:2022-03-28 22:56:35 

摘要:现在在项目中使用的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

MybatisPlus整合Flowable出现的坑及解决

Flowable:ModelerDatabaseConfiguration.class

MybatisPlus整合Flowable出现的坑及解决

注解解释

@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);
               }
           }
       }
   }

}

来源:https://blog.csdn.net/forever_xw_/article/details/122377609

标签:MybatisPlus,整合,Flowable
0
投稿

猜你喜欢

  • 深入理解Spring Boot的日志管理

    2021-11-16 09:58:40
  • 支持SpEL表达式的自定义日志注解@SysLog介绍

    2023-08-27 09:38:42
  • 【MyBatis源码全面解析】MyBatis一二级缓存介绍

    2023-02-25 23:57:12
  • java如何用Processing生成马赛克风格的图像

    2023-11-07 20:52:44
  • Android 6.0区别U盘和SD卡设备的方法详解

    2022-09-09 13:10:58
  • Java Collections集合继承结构图_动力节点Java学院整理

    2022-07-10 03:44:53
  • java实现删除某条信息并刷新当前页操作

    2022-06-26 07:12:12
  • Java实战之用hutool-db实现多数据源配置

    2023-11-28 19:37:10
  • Android开发实现读取Assets下文件及文件写入存储卡的方法

    2023-02-07 15:42:21
  • C语言中求字符串长度的函数的几种实现方法

    2023-07-04 23:29:05
  • Android可配置透明度的水印

    2021-06-06 14:07:42
  • C#装箱和拆箱原理详解

    2021-12-29 16:07:26
  • java日期操作工具类(获取指定日期、日期转换、相隔天数)

    2023-11-28 06:42:53
  • spring cloud Ribbon用法及原理解析

    2021-11-28 15:27:21
  • C#禁止textbox复制、粘贴、剪切及鼠标右键的方法

    2022-08-21 09:13:40
  • Java对XML文件增删改查操作示例

    2021-10-28 08:46:29
  • 教你在 Java 中实现 Dijkstra 最短路算法的方法

    2023-04-03 00:19:42
  • Java CAS操作与Unsafe类详解

    2023-06-15 10:06:49
  • Android双击事件拦截方法

    2022-07-21 19:33:30
  • 本地jvm执行flink程序带web ui的操作

    2022-09-03 20:49:00
  • asp之家 软件编程 m.aspxhome.com