0

I am using Oracle AQ with spring boot with as follows:

Gradle dependency:

implementation "com.oracle.database.spring:oracle-spring-boot-starter-aqjms:23.4.0"

JmsConfiguration:

    @Configuration
    @EnableJms
    public class JmsConfiguration {
    
        @Bean
        public ConnectionFactory connectionFactory(DataSource dataSource) {
            return AQjmsFactory.getQueueConnectionFactory(dataSource);
        }

Now I try to set up some properties for Oracle Universal Connection Pool via application.yaml based on this oracle docs, but properties are not applied:

spring:
  datasource:
    url: jdbc:oracle:thin:@localhost:1521/ORCLPDB1
    username: AQ_USER
    password: your_password
    oracleucp:
      initial-pool-size: 5
      min-pool-size: 10
      max-pool-size: 30
      connection-wait-timeout: 2
      connection-factory-class-name: oracle.jdbc.pool.OracleDataSource
      connection-pool-name: some_pool_name
    type: oracle.ucp.jdbc.PoolDataSource

Whereas if I am setting them via code, then it works:

import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSException;
import oracle.jakarta.jms.AQjmsFactory;
import oracle.ucp.jdbc.PoolDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;

import java.sql.SQLException;

@Configuration
@EnableJms
public class JmsConfiguration {

    @Bean
    public ConnectionFactory connectionFactory(PoolDataSource poolDataSource) throws JMSException, SQLException {
        poolDataSource.setInitialPoolSize(5);
        poolDataSource.setMinPoolSize(10);
        poolDataSource.setMaxPoolSize(30);
        poolDataSource.setConnectionWaitTimeout(3000);

        return AQjmsFactory.getQueueConnectionFactory(poolDataSource);
    }

To see if the settings were applied or not, I use this:

import oracle.ucp.jdbc.PoolDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.event.EventListener;

import java.sql.SQLException;
import java.util.List;

@SpringBootApplication
@ConfigurationPropertiesScan
public class RequestBufferingServiceApplication {

    @Autowired
    PoolDataSource poolDataSource;

    public static void main(String[] args) {
        SpringApplication.run(RequestBufferingServiceApplication.class, args);
    }

    @EventListener(ApplicationReadyEvent.class)
    public void foo() throws SQLException {
        System.out.println("------");
        System.out.println("Init pool size: " + poolDataSource.getInitialPoolSize());
        System.out.println("Min pool size: " + poolDataSource.getMinPoolSize());
        System.out.println("Max pool size: " + poolDataSource.getMaxPoolSize());
        System.out.println("ConnectionWaitTimeout: " + poolDataSource.getConnectionWaitTimeout());
        System.out.println("------");
    }
}

How to apply Oracle UCP properties via application.yaml properly?

EDIT:

Output with no impact of application.yaml:

------
Init pool size: 0
Min pool size: 0
Max pool size: 2147483647
ConnectionWaitTimeout: 3
------

Output with impact of java config (desired):

------
Init pool size: 5
Min pool size: 10
Max pool size: 30
ConnectionWaitTimeout: 2
------

build.gradle:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.3'
    id 'io.spring.dependency-management' version '1.1.6'
    id 'io.freefair.lombok' version '8.11'
    id "io.qameta.allure-report" version "2.11.2"
    id 'org.sonarqube' version '5.0.0.4638'
    id 'jacoco'
}

group = 'de.telekom.mff'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

bootJar {
    archiveFileName = "request-buffering-service.${archiveExtension.get()}"
}

jar {
    enabled = true
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

ext {
    versions = [
            oracleSpringBootStarterAqjms: "23.4.0",
            allureCucumber7Jvm          : "2.27.0",
            testcontainers              : "1.20.1",
            springCloud                 : "2023.0.3",
            awaitility                  : "4.2.2",
            xmlUnit                     : "2.10.0",
            jsonUnitAssertj             : "3.2.2",
            wiremock                    : "4.1.4"
    ]
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${versions.springCloud}"
    }
}

dependencies {
    implementation "org.springframework.boot:spring-boot-starter-web"
    implementation "org.springframework.boot:spring-boot-starter-webflux"
    implementation "org.springframework.boot:spring-boot-starter-log4j2"
    implementation "org.springframework.boot:spring-boot-starter-actuator"
    implementation "org.springframework:spring-aspects"
    implementation "org.springframework.cloud:spring-cloud-starter-kubernetes-fabric8-config"
    implementation "org.springframework.cloud:spring-cloud-kubernetes-fabric8-leader"
    implementation "com.oracle.database.spring:oracle-spring-boot-starter-aqjms:${versions.oracleSpringBootStarterAqjms}"
    testImplementation "org.springframework.boot:spring-boot-starter-test"
    testImplementation "io.fabric8:kubernetes-server-mock"
    testImplementation "org.springframework.cloud:spring-cloud-contract-wiremock:${versions.wiremock}"
    testImplementation "org.testcontainers:oracle-free:${versions.testcontainers}"
    testImplementation "org.testcontainers:junit-jupiter:${versions.testcontainers}"
    testImplementation "org.awaitility:awaitility:${versions.awaitility}"
    testImplementation "org.xmlunit:xmlunit-core:${versions.xmlUnit}"
    testImplementation "io.qameta.allure:allure-cucumber7-jvm:${versions.allureCucumber7Jvm}"
    testImplementation "net.javacrumbs.json-unit:json-unit-assertj:${versions.jsonUnitAssertj}"
    testRuntimeOnly "org.junit.platform:junit-platform-launcher"
}

Spring start debug log (using 23.4.0 aqjms starter, where url, user, password for db are auto configured via application.yaml):

Negative matches:

DataSourceAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' (OnClassCondition)

DataSourceInitializationConfiguration: Did not match: - @ConditionalOnClass did not find required class 'org.springframework.jdbc.datasource.init.DatabasePopulator' (OnClassCondition)

DataSourceTransactionManagerAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'org.springframework.jdbc.core.JdbcTemplate' (OnClassCondition)

16
  • Which Spring Boot version are you using? Which OracleUCP version are you using? Please include your pom.xml. Also what was the output of your test to see if values are applied or not? Are you manually defining a DataSource bean, or are you using only auto configuration? Commented Jan 8 at 14:34
  • @M.Deinum, I edited my question, pls have a look. Spring boot version is 3.3.3, for oracle I use only oracle-spring-boot-starter-aqjms dependency, so oracle ucp 21.9.0.0 is included into starter. autoconfig. Regarding datasource - I am using only autoconfig. Commented Jan 8 at 22:20
  • All the other properties are being applied? I do think so as you use a PooledDataSource for the injection. What happens if you turn your yaml file into a properties file? I wonder if the - pose a problem when binding. Can you expose the connection-pool-name as well and then set the spring.datasource.name property to something? That should set the connectionPoolName property if the proper config class kicks in. Commented Jan 9 at 5:57
  • @M.Deinum, all other properties are applied, like datasource url, user and so on, so I can send smith in the queue and I see it in queue table. I also tried with properties instead of yaml and now tried to set spring.datasource.name - nothing changed. Commented Jan 9 at 9:10
  • Then something is preventing the specific OracleUCP configuration to kick in. What happens if you run with debug=true or --debug. It should tell you why the DataSourceConfiguration.OracleUcp isn't applied. Commented Jan 9 at 9:14

1 Answer 1

1

The oracle-spring-boot-starter-aqjms contains auto-configuration itself which will configure the DataSource and ConnectionFactory.

This configuration that kicks in when including this starter. The configuration will only apply the spring.datasource.url, spring.datasource.username and spring.datasource.password properties and ignore the other ones. Now as there is a pre-configured DataSource the auto-configuration from Spring Boot itself doesn't apply

Version 23.4.0

The oracle-spring-boot-starter-aqjms (version 23.4.0) contains auto configuration for the DataSource and ConnectionFactory. This configuration isn't part of the oracle-spring-boot-starter-ucp which will take the regular Spring Boot configuration.

Which explains why it works.

So if you want to use the full Spring Boot datasource configuration you would need to exclude the com.oracle.spring.aqjms.AqJmsAutoConfiguration from being applied.

@SpringBootApplication(excludeName = {"com.oracle.spring.aqjms.AqJmsAutoConfiguration"})

or you can add an exclude to your application.yml.

spring:
  autoconfigure:
    exclude: com.oracle.spring.aqjms.AqJmsAutoConfiguration

Version 24.4.0

Now for the oracle-spring-boot-starter-aqjms version 24.4.0 things have changed and the auto configuration for the datasource moved to the oracle-spring-boot-starter-ucp instead. So for that to work you would need to exclude a different auto-config the com.oracle.spring.ucp.UCPAutoConfiguration which you can exclude in either of the ways mentioned above.

With the exclude in place, when running the application you will now have a properly configured Oracle Pooled Datasource as the regular Spring Boot auto-configuration will kick in. Or at least the one you expected to be there.

Caveat

The Spring Boot auto configuration for a DataSource, at the moment of writing this answer, does require spring-jdbc to be present on the classpath. This is due the check for both javax.sql.DataSource and the org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType from spring-jdbc.

See also https://github.com/spring-projects/spring-boot/issues/43786

Sign up to request clarification or add additional context in comments.

13 Comments

That is not what I would like to achieve, because if I will exclude auto configuration from 23.4.0, I will not have any auto configured PooledDataSource at all thus I have to create this bean manually. The question was why oracle ucp properties from application.yaml are not applied whereas url, user, password are applied
But it seems that there is no other way to achieve it except of manually bean creation
If I exclude the Oracle auto-configuration class the regular Spring datasource is created for me. If that is not the case in situation you must have excluded other things. Why it doesn't work is explained in my answer, as that configuration from oracle only uses url, user and password and nothing else. So disable the auto-config to let the Spring Boot auto configured datasource be created. You should exclude the class (as I have done) not exclude the dependency.
So in short, add the dependency, exclude the Oracle specific auto-configuration and you will have the correctly configured datasource. At least that is what I have in my working sample based of your code.
I did create this issue for Spring Boot to get some feedback from the maintainers. Just interested to see if it was intentional or not.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.