快捷搜索:

阿里生态项目加入Activiti7遇到初始化异常的问题

在阿里生态项目(nacos/dubbo/sentinel/seata)里面加入Activiti7,出现下面异常,初始化拿不到数据库链接 排查的过程一波三折,经过一番捣鼓发现是druid的连接抛出的异常: com.alibaba.druid.pool.DruidPooledConnection#setSchema public void setSchema(String schema) throws SQLException { throw new SQLFeatureNotSupportedException(); } 我用的是默认的HikariDataSource,怎么冒出个druid??查依赖。

翻查依赖树发现spring-cloud-starter-alibaba-nacos-config和seata-all两个包依赖了druid,于是在依赖里面排除druid,启动正常了。

于是就发了一条issue给seata,得到的回复是seata依赖druid是为了用它的sqlparser, 也就是说,用排除Druid的方法是不能真正解决问题的,会给seata带来异常隐患!

因为看依赖树并没发现有druid-spring-boot-starter,也并没在配置里面有druid的参数,理应不会自动配置druidsource的!于是再继续查!

最后发现依赖里面的baomidou动态数据源导致:

    com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceCreatorAutoConfiguration.DruidDataSourceCreatorConfiguration#druidDataSourceCreator 只要发现有druid的依赖就会建立DruidDataSourceCreator
/**
     * 存在Druid数据源时, 加入创建器
     */
    @ConditionalOnClass(DruidDataSource.class)
    @Configuration
    public class DruidDataSourceCreatorConfiguration {
          
   
        @Bean
        @Order(DRUID_ORDER)
        @ConditionalOnMissingBean
        public DruidDataSourceCreator druidDataSourceCreator() {
          
   
            return new DruidDataSourceCreator(properties);
        }

    }

    /**
     * 存在Hikari数据源时, 加入创建器
     */
    @ConditionalOnClass(HikariDataSource.class)
    @Configuration
    public class HikariDataSourceCreatorConfiguration {
          
   
        @Bean
        @Order(HIKARI_ORDER)
        @ConditionalOnMissingBean
        public HikariDataSourceCreator hikariDataSourceCreator() {
          
   
            return new HikariDataSourceCreator(properties);
        }
    }

最后将兼容的Datasource收集到com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator.creators 然后做匹配,因为Druid先于Hikari,所以就抢占了:

public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
          
   
        DataSourceCreator dataSourceCreator = null;
        for (DataSourceCreator creator : this.creators) {
          
   
            if (creator.support(dataSourceProperty)) {
          
   
                dataSourceCreator = creator;
                break;
            }
        }
        if (dataSourceCreator == null) {
          
   
            throw new IllegalStateException("creator must not be null,please check the DataSourceCreator");
        }
        return dataSourceCreator.createDataSource(dataSourceProperty);
    }

找到原因就好办,DataSourceCreattor要通过support返回当前creator是否支持app配置,而其中会用上type这个条件:

@Override
    public boolean support(DataSourceProperty dataSourceProperty) {
          
   
        Class<? extends DataSource> type = dataSourceProperty.getType();
        return (type == null && druidExists) || (type != null && DRUID_DATASOURCE.equals(type.getName()));
    }

所以,最终完美的解决方法不是用pom排除,也不是放弃使用动态数据源,而是在配置文件中指定type:

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://127.0.0.1:3306/seata_sample_nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&nullCatalogMeansCurrent=true
          username: root
          password: 123456
          type: com.zaxxer.hikari.HikariDataSource

Druid不是一般的烂!

经验分享 程序员 职场和发展