SpringBoot多数据源unsatisfied dependency expressed through method 'entityManagerFactoryBuilder...
SpringBoot多数据源unsatisfied dependency expressed through method 'entityManagerFactoryBuilder...

SpringBoot多数据源unsatisfied dependency expressed through method 'entityManagerFactoryBuilder...

轩灵
2018-10-08 / 0 评论 / 1,566 阅读 /
  • 文章转载请注明来源!
  • / 正在检测是否收录...
    温馨提示:
    本文最后更新于2022年03月19日,已超过768天没有更新,若内容或图片失效,请留言反馈。

    本来的项目(基于SpringBoot 2.0.5-RELEASE)集成了JPA、mybatis的注解、XML方式访问DB。
    后面集成多数据源的时候启动SpringBoot时出现了如下错误:

    ERROR 32320 — [main] com.zaxxer.hikari.HikariConfig : HikariPool-1 - jdbcUrl is required with driverClassName.

    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method ‘entityManagerFactory’ parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘entityManagerFactoryBuilder’ defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method ‘entityManagerFactoryBuilder’ parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘jpaVendorAdapter’ defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method ‘jpaVendorAdapter’ threw exception; nested exception is java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:732)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:474)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1247)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1096)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:859)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:780)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:333)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:139)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
    … 24 more

    后来查看了源码,流程如下:

    @Bean(name = "test1DataSource")
        @ConfigurationProperties(prefix = "spring.datasource")
        @Primary
        public DataSource testDataSource() {
            return DataSourceBuilder.create().build();
        }

    进入DataSourceBuilder.create().build():

    public T build() {
            Class<? extends DataSource> type = getType();
            DataSource result = BeanUtils.instantiateClass(type);
            maybeGetDriverClassName();
            bind(result);
            return (T) result;
        }

    maybeGetDriverClassName(); 方法:

    private void maybeGetDriverClassName() {
            if (!this.properties.containsKey("driverClassName")
                    && this.properties.containsKey("url")) {
                String url = this.properties.get("url");
                String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
                this.properties.put("driverClassName", driverClass);
            }
        }

    bind(result) 方法:

    private void bind(DataSource result) {
            ConfigurationPropertySource source = new MapConfigurationPropertySource(
                    this.properties);
            ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();
            aliases.addAliases("url", "jdbc-url");
            aliases.addAliases("username", "user");
            Binder binder = new Binder(source.withAliases(aliases));
            binder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(result));
        }

    因为springboot首推的连接池使用了HikariCP连接池,GET到这个点, HikariDataSource的获取数据库连接的getConnection方法:

    @Override
       public Connection getConnection() throws SQLException
       {
          if (isClosed()) {
             throw new SQLException("HikariDataSource " + this + " has been closed.");
          }
          if (fastPathPool != null) {
             return fastPathPool.getConnection();
          }
          // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
          HikariPool result = pool;
          if (result == null) {
             synchronized (this) {
                result = pool;
                if (result == null) {
                   validate();
                   LOGGER.info("{} - Starting...", getPoolName());
                   try {
                      pool = result = new HikariPool(this);
                      this.seal();
                   }
                   catch (PoolInitializationException pie) {
                      if (pie.getCause() instanceof SQLException) {
                         throw (SQLException) pie.getCause();
                      }
                      else {
                         throw pie;
                      }
                   }
                   LOGGER.info("{} - Start completed.", getPoolName());
                }
             }
          }
          return result.getConnection();
       }

    HikariConfig的validate方法

    public void validate()
       {
          if (poolName == null) {
             poolName = generatePoolName();
          }
          else if (isRegisterMbeans && poolName.contains(":")) {
             throw new IllegalArgumentException("poolName cannot contain ':' when used with JMX");
          }
          // treat empty property as null
          catalog = getNullIfEmpty(catalog);
          connectionInitSql = getNullIfEmpty(connectionInitSql);
          connectionTestQuery = getNullIfEmpty(connectionTestQuery);
          transactionIsolationName = getNullIfEmpty(transactionIsolationName);
          dataSourceClassName = getNullIfEmpty(dataSourceClassName);
          dataSourceJndiName = getNullIfEmpty(dataSourceJndiName);
          driverClassName = getNullIfEmpty(driverClassName);
          jdbcUrl = getNullIfEmpty(jdbcUrl);
          // Check Data Source Options
          if (dataSource != null) {
             if (dataSourceClassName != null) {
                LOGGER.warn("{} - using dataSource and ignoring dataSourceClassName.", poolName);
             }
          }
          else if (dataSourceClassName != null) {
             if (driverClassName != null) {
                LOGGER.error("{} - cannot use driverClassName and dataSourceClassName together.", poolName);
                // NOTE: This exception text is referenced by a Spring Boot FailureAnalyzer, it should not be
                // changed without first notifying the Spring Boot developers.
                throw new IllegalStateException("cannot use driverClassName and dataSourceClassName together.");
             }
             else if (jdbcUrl != null) {
                LOGGER.warn("{} - using dataSourceClassName and ignoring jdbcUrl.", poolName);
             }
          }
          else if (jdbcUrl != null || dataSourceJndiName != null) {
             // ok
          }
          else if (driverClassName != null) {
             LOGGER.error("{} - jdbcUrl is required with driverClassName.", poolName);
             throw new IllegalArgumentException("jdbcUrl is required with driverClassName.");
          }
          else {
             LOGGER.error("{} - dataSource or dataSourceClassName or jdbcUrl is required.", poolName);
             throw new IllegalArgumentException("dataSource or dataSourceClassName or jdbcUrl is required.");
          }
          validateNumerics();
          if (LOGGER.isDebugEnabled() || unitTest) {
             logConfiguration();
          }
       }

    这个if分支:

    jdbcUrl = getNullIfEmpty(jdbcUrl);
    else if (driverClassName != null) {
             LOGGER.error("{} - jdbcUrl is required with driverClassName.", poolName);
             throw new IllegalArgumentException("jdbcUrl is required with driverClassName.");
          }

    这里要求DataSource的参数存在 jdbcUrl 、以及driverClassName,而我们的配置是:

    spring.datasource.url=jdbc:mysql://localhost:3306/mypydb
    spring.datasource.username=root
    spring.datasource.password=11111111
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource2.url=jdbc:mysql://localhost:3306/mypydb2
    spring.datasource2.username=root
    spring.datasource2.password=11111111
    spring.datasource2.driver-class-name=com.mysql.jdbc.Driver

    所以将url改为 jdbc-url 即可。

    spring.datasource.jdbc-url=jdbc:mysql://localhost:3306/mypydb
    spring.datasource2.jdbc-url=jdbc:mysql://localhost:3306/mypydb2
    本文共 116 个字数,平均阅读时长 ≈ 1分钟
    118

    海报

    点点赞赏,手留余香

    给TA打赏
    如果觉得文章对您有用,快来赞赏一个吧!
      取消
      扫码打赏
      支付金额随意哦!

      评论 (0)

      语录
      取消