How to set data source class name for HikariCP in application.yml of spring boot application

20 views Asked by At

Learning from the document of HikariCP we know there is a property "dataSourceClassName" to define a class to create database connection, it works fine if I build the HikariCP in programming:

HikariConfig config = new HikariConfig();
config.setUsername("");
config.setDataSourceClassName("com.my.own.DataSource");
HikariDataSource hikariDs = new HikariDataSource(config);
// database accessing with hikariDs created above
// ...

But when I try to configure the data source class name in the application.yml file of a spring boot application, it can not work, here is the config:

spring:
  datasource:
    url: ${jdbc_url}
    hikari:
      dataSourceClassName: com.my.own.DataSource
      maximum-pool-size: 64

And here is the error from HikariCP:

java.lang.IllegalStateException: cannot use driverClassName and dataSourceClassName together.
    at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1011)

The error above is very clear, we can not set driverClassName and dataSourceClassName together, after check the source code of spring boot, I find out the the driverClassName is from property spring.datasource.url:

// org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration#createDataSource
    private static <T> T createDataSource(JdbcConnectionDetails connectionDetails, Class<? extends DataSource> type,
            ClassLoader classLoader) {
        return (T) DataSourceBuilder.create(classLoader)
            .type(type)
            .driverClassName(connectionDetails.getDriverClassName())
            .url(connectionDetails.getJdbcUrl())
            .username(connectionDetails.getUsername())
            .password(connectionDetails.getPassword())
            .build();
    }
// org.springframework.boot.jdbc.DataSourceBuilder#build
public T build() {
        DataSourceProperties<T> properties = DataSourceProperties.forType(this.classLoader, this.type);
        DataSourceProperties<DataSource> deriveFromProperties = getDeriveFromProperties();
        Class<? extends T> instanceType = (this.type != null) ? this.type : properties.getDataSourceInstanceType();
        T dataSource = BeanUtils.instantiateClass(instanceType);
        Set<DataSourceProperty> applied = new HashSet<>();
        for (DataSourceProperty property : DataSourceProperty.values()) {
            String value = this.values.get(property);
            if (value == null && deriveFromProperties != null && properties.canSet(property)) {
                value = deriveFromProperties.get(this.deriveFrom, property);
            }
            if (value != null) {
                properties.set(dataSource, property, value);
                applied.add(property);
            }
        }
        if (!applied.contains(DataSourceProperty.DRIVER_CLASS_NAME)
                && properties.canSet(DataSourceProperty.DRIVER_CLASS_NAME)
                && this.values.containsKey(DataSourceProperty.URL)) {
            String url = this.values.get(DataSourceProperty.URL);
            DatabaseDriver driver = DatabaseDriver.fromJdbcUrl(url);
            properties.set(dataSource, DataSourceProperty.DRIVER_CLASS_NAME, driver.getDriverClassName());
        }
        return dataSource;
    }

By reading above code, we can see that the driverClassName will be set if there is spring.datasource.url existing, and spring.datasource.url is a mandatory property if you are not using embedded database. So for my understanding, we can not set the data source class name in the application.yml, if I want to define a customized data source class, I need to do it in programming like this:

@Configuration
public class DatabaseConfig {
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setUsername("");
        config.setDataSourceClassName("com.my.own.DataSource");
        return new HikariDataSource(config);
    }

Am I right?

0

There are 0 answers