Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for com.baomidou:dynamic-datasource-spring-boot-starter:3.6.1 #154

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
"jni-config.json",
"proxy-config.json",
"reflect-config.json",
"resource-config.json",
"serialization-config.json"
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lambdaCapturingTypes": [],
"types": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"latest": true,
"metadata-version": "3.6.1",
"module": "com.baomidou:dynamic-datasource-spring-boot-starter",
"tested-versions": [
"3.6.1"
]
}
]
4 changes: 4 additions & 0 deletions metadata/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@
"directory": "org.eclipse.jetty/jetty-client",
"module": "org.eclipse.jetty:jetty-client"
},
{
"directory": "com.baomidou/dynamic-datasource-spring-boot-starter",
"module": "com.baomidou:dynamic-datasource-spring-boot-starter"
},
{
"directory": "io.opentelemetry/opentelemetry-exporter-jaeger",
"module": "io.opentelemetry:opentelemetry-exporter-jaeger"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gradlew.bat
gradlew
gradle/
build/
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright and related rights waived via CC0
*
* You should have received a copy of the CC0 legalcode along with this
* work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/

plugins {
id "org.graalvm.internal.tck"
id 'org.springframework.boot' version '3.0.1'
id 'io.spring.dependency-management' version '1.1.0'
}

String libraryVersion = tck.testedLibraryVersion.get()

dependencies {
testImplementation "com.baomidou:dynamic-datasource-spring-boot-starter:$libraryVersion"
testImplementation 'org.assertj:assertj-core:3.22.0'
testImplementation 'org.springframework.boot:spring-boot-starter-web'
testRuntimeOnly 'com.h2database:h2:2.1.214'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

group 'com_baomidou.dynamic_datasource_spring_boot_starter'

springBoot {
mainClass = 'com_baomidou.dynamic_datasource_spring_boot_starter.AddRemoveDatasourceApplication'
}

graalvmNative {
agent {
defaultMode = "conditional"
modes {
conditional {
userCodeFilterPath = "user-code-filter.json"
}
}
metadataCopy {
mergeWithExisting = true
inputTaskNames.add("test")
outputDirectories.add("src/test/resources/META-INF/native-image/com.baomidou/dynamic-datasource-spring-boot-starter")
}
}
}
Comment on lines +30 to +44
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sdeleuze

  • Hi, I noticed that when Spring Boot's Gradle Plugin is introduced, the following error will occur when executing ./gradlew -Pagent clean test.
01:21:29.638 [main] INFO org.springframework.test.context.aot.TestClassScanner - Scanning for Spring test classes in all packages in classpath roots [/home/linghengqian/TwinklingLiftWorks/git/public/graalvm-trace-metadata-smoketest/dynamic-datasource-spring-boot-starter/build/classes/java/test, /home/linghengqian/TwinklingLiftWorks/git/public/graalvm-trace-metadata-smoketest/dynamic-datasource-spring-boot-starter/build/resources/test]
Exception in thread "main" java.lang.IllegalStateException: Cannot perform AOT processing during AOT run-time execution
        at org.springframework.util.Assert.state(Assert.java:76)
        at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:126)
        at org.springframework.test.context.aot.TestAotProcessor.performAotProcessing(TestAotProcessor.java:91)
        at org.springframework.test.context.aot.TestAotProcessor.doProcess(TestAotProcessor.java:72)
        at org.springframework.test.context.aot.TestAotProcessor.doProcess(TestAotProcessor.java:39)
        at org.springframework.context.aot.AbstractAotProcessor.process(AbstractAotProcessor.java:82)
        at org.springframework.boot.test.context.SpringBootTestAotProcessor.main(SpringBootTestAotProcessor.java:57)

Copy link
Collaborator

@sdeleuze sdeleuze Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@linghengqian Looks like Native Build Tools sets org.graalvm.nativeimage.imagecode system property when the agent profile is enabled (expected) but that impacts the code running in the Gradle plugin JVM potentially because the JVM is not forked and in term of lifecycle that maybe happens too early.

@bclozel @sbrannen Any thoughts ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running in agent mode with the NBT will set org.graalvm.nativeimage.imagecode=agent.

And AotDetector.useGeneratedArtifacts() returns true if that's the case.

So that would explain the cause of the IllegalStateException in TestContextAotGenerator.

That may be problematic in and of itself.


In any case, why is TestContextAotGenerator used when executing ./gradlew -Pagent clean test?

Is that command supposed to trigger AOT processing of the test suite?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sbrannen

  • This involves an idea that I want to use GraalVM Tracing Agent to collect GraalVM Reachability Metadata in Conditional form for the corresponding unit tests for some third-party Spring Boot Starters that must use Spring Boot's unique classes.

  • I've been involved with too many deadlines lately, and haven't had time to investigate this PR.

  • Do you want me to open a new issue with a minimal reproducible example on the Spring Boot side?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want me to open a new issue with a minimal reproducible example on the Spring Boot side?

@linghengqian, yes that would be great!

Though it may be better to file the issue against the Spring Framework, since changes will likely need to be made in Framework -- even if the example you provide uses Boot and its plugins.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want me to open a new issue with a minimal reproducible example on the Spring Boot side?

@linghengqian, yes that would be great!

Though it may be better to file the issue against the Spring Framework, since changes will likely need to be made in Framework -- even if the example you provide uses Boot and its plugins.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
library.version = 3.6.1
metadata.dir = com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pluginManagement {
def tckPath = Objects.requireNonNullElse(
System.getenv("GVM_TCK_TCKDIR"),
"../../../../tck-build-logic"
)
includeBuild(tckPath)
}

plugins {
id "org.graalvm.internal.tck-settings" version "1.0.0-SNAPSHOT"
}

rootProject.name = 'com.baomidou.dynamic-datasource-spring-boot-starter_tests'
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright and related rights waived via CC0
*
* You should have received a copy of the CC0 legalcode along with this
* work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
package com_baomidou.dynamic_datasource_spring_boot_starter;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.hikari.HikariCpConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

@SpringBootTest(classes = AddRemoveDatasourceApplication.class, webEnvironment = RANDOM_PORT)
public class AddRemoveDatasourceTest {
@Autowired
DataSource dataSource;
@Autowired
DefaultDataSourceCreator dataSourceCreator;

@Test
void testAddAndRemoveDataSource() {
HikariCpConfig hikariCpConfig = new HikariCpConfig();
hikariCpConfig.setConnectionTestQuery("select 1");
DataSourceProperty dataSourceProperty = new DataSourceProperty()
.setPoolName("slave_1").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test1;MODE=MySQL")
.setUsername("sa").setPassword("").setHikari(hikariCpConfig);
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
ds.addDataSource(dataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(dataSourceProperty));
assertThat(ds.getDataSources().keySet()).contains("slave_1");
ds.removeDataSource("slave_1");
assertThat(ds.getDataSources().keySet()).doesNotContain("slave_1");
}
}

@SpringBootApplication
class AddRemoveDatasourceApplication {
public static void main(String[] args) {
SpringApplication.run(AddRemoveDatasourceApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright and related rights waived via CC0
*
* You should have received a copy of the CC0 legalcode along with this
* work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
package com_baomidou.dynamic_datasource_spring_boot_starter;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

@SpringBootTest(classes = LoadDatasourceFromJDBCApplication.class, webEnvironment = RANDOM_PORT)
public class LoadDatasourceFromJDBCTest {
@Autowired
DataSource dataSource;

@Test
void testExistDataSource() {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
assertThat(ds.getDataSources().keySet()).contains("master", "db1", "db2", "db3");
}
}

@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"})
@SpringBootApplication
class LoadDatasourceFromJDBCApplication {

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

@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
return new AbstractJdbcDataSourceProvider("org.h2.Driver", "jdbc:h2:mem:test;MODE=MySQL", "sa", "") {
@Override
protected Map<String, DataSourceProperty> executeStmt(Statement statement) throws SQLException {
statement.execute("""
CREATE TABLE IF NOT EXISTS `DB`
(
`name` VARCHAR(30) NULL DEFAULT NULL,
`username` VARCHAR(30) NULL DEFAULT NULL,
`password` VARCHAR(30) NULL DEFAULT NULL,
`url` VARCHAR(30) NULL DEFAULT NULL,
`driver` VARCHAR(30) NULL DEFAULT NULL
)""");
statement.executeUpdate("insert into DB values ('master','sa','','jdbc:h2:mem:test;MODE=MySQL','org.h2.Driver')");
statement.executeUpdate("insert into DB values ('db1','sa','','jdbc:h2:mem:test2','org.h2.Driver')");
statement.executeUpdate("insert into DB values ('db2','sa','','jdbc:h2:mem:test3','org.h2.Driver')");
statement.executeUpdate("insert into DB values ('db3','sa','','jdbc:h2:mem:test4','org.h2.Driver')");
Map<String, DataSourceProperty> map = new HashMap<>();
ResultSet rs = statement.executeQuery("select * from DB");
while (rs.next()) {
map.put(rs.getString("name"), new DataSourceProperty()
.setUsername(rs.getString("username")).setPassword(rs.getString("password"))
.setUrl(rs.getString("url")).setDriverClassName(rs.getString("driver")));
}
return map;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright and related rights waived via CC0
*
* You should have received a copy of the CC0 legalcode along with this
* work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
package com_baomidou.dynamic_datasource_spring_boot_starter;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com_baomidou.dynamic_datasource_spring_boot_starter.service.nest.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

@SpringBootTest(classes = NestApplication.class, webEnvironment = RANDOM_PORT)
public class NestDataSourceTest {
@Autowired
DataSource dataSource;
@Autowired
DefaultDataSourceCreator dataSourceCreator;
@Autowired
private TeacherService teacherService;
@Autowired
private StudentService studentService;
@Autowired
private SchoolService schoolService;

@Test
void testNest() {
DataSourceProperty masterDataSourceProperty = new DataSourceProperty()
.setPoolName("master").setDriverClassName("org.h2.Driver")
.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'")
.setUsername("sa").setPassword("");
DataSourceProperty teacherDataSourceProperty = new DataSourceProperty()
.setPoolName("teacher").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE")
.setUsername("sa").setPassword("");
DataSourceProperty studentDataSourceProperty = new DataSourceProperty()
.setPoolName("student").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE")
.setUsername("sa").setPassword("");
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty));
ds.addDataSource(teacherDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(teacherDataSourceProperty));
ds.addDataSource(studentDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(studentDataSourceProperty));
assertThat(ds.getDataSources().keySet()).contains("master", "teacher", "student");
assertThat(teacherService.addTeacherWithTx("ss", 1)).isEqualTo(1);
assertThat(studentService.addStudentWithTx("tt", 2)).isEqualTo(1);
assertThat(teacherService.selectTeachers()).isEqualTo(List.of(new Teacher(1, "tt", 2)));
assertThat(studentService.selectStudents()).isEqualTo(List.of(new Student(1, "tt", 2)));
assertThat(schoolService.addTeacherAndStudentWithTx()).isEqualTo(2);
assertThat(teacherService.selectTeachers()).isEqualTo(List.of(new Teacher(1, "tt", 2), new Teacher(2, "bb", 4)));
assertThat(studentService.selectStudents()).isEqualTo(List.of(new Student(1, "tt", 2), new Student(2, "bb", 4)));
}
}

@SpringBootApplication
class NestApplication {
public static void main(String[] args) {
SpringApplication.run(NestApplication.class, args);
}
}
Loading