content: package com.seezoon.dao.autoconfigure;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  import java.time.Duration;
  
  import org.mybatis.spring.annotation.MapperScan;
  import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.autoconfigure.AutoConfigureAfter;
  import org.springframework.context.ApplicationContext;
  import org.springframework.context.annotation.ComponentScan;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.context.annotation.PropertySource;
  import org.springframework.retry.support.RetryTemplate;
  import org.springframework.transaction.annotation.EnableTransactionManagement;
  
  import com.zaxxer.hikari.HikariDataSource;
  
  import lombok.RequiredArgsConstructor;
  
  /**
   * <p>
   * {@code  @ComponentScan} 可以省略，但idea dao 注入有错误提示规避
   * 为了让连接池属性尽量默认，使用{@code @PropertySource("default-datasource.properties")}
   * 这里不能用application.properties相关名称.配置中字段可以被外部配置或者引用该组件方覆盖
   * </p>
   *
   * @author hdf
   */
  @Configuration
  @MapperScan("com.seezoon.dao.modules.*")
  @ComponentScan("com.seezoon.dao.modules.*")
  @PropertySource("classpath:default-datasource.properties")
  @AutoConfigureAfter({MybatisAutoConfiguration.class})
  @EnableTransactionManagement(proxyTargetClass = true)
  @RequiredArgsConstructor(onConstructor = @__(@Autowired))
  public class SeezoonDaoAutoConfiguration implements InitializingBean {
  
      private final ApplicationContext applicationContext;
  
      /**
       * hikari 默认不会初始化DB
       */
      private void dataSourceInit() {
          HikariDataSource hikariDataSource = applicationContext.getBean(HikariDataSource.class);
          if (hikariDataSource.isRunning()) {
              return;
          }
  
          // 首次2s后重试,下次 4 ，8 ，16
          // 最少1分钟一次
          RetryTemplate retryTemplate = RetryTemplate.builder().infiniteRetry()
              .exponentialBackoff(Duration.ofSeconds(2).toMillis(), 2, Duration.ofMinutes(1).toMillis()).build();
          retryTemplate.execute((context) -> {
              // 自动关闭，释放连接
              try (Connection ignored = hikariDataSource.getConnection();) {
              } catch (SQLException e) {
                  throw new RuntimeException(String.format("Datasource Init Error attempt {} times ,Because {}",
                      context.getRetryCount() + 1, e.getMessage()));
              }
              return 0;
          });
      }
  
      @Override
      public void afterPropertiesSet() throws Exception {
          this.dataSourceInit();
      }
  }
  