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)
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
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
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.
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