Skip to content

Commit 152a7f9

Browse files
authored
bugfix: the drivers in the lib folder cannot be loaded (#7354)
1 parent f5694b4 commit 152a7f9

File tree

6 files changed

+125
-56
lines changed

6 files changed

+125
-56
lines changed

changes/en-us/2.x.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Add changes here for all PR submitted to the 2.x branch.
2626
### bugfix:
2727

2828
- [[#7349](https://github.com/apache/incubator-seata/pull/7349)] Resolve NullPointerException in EtcdRegistryServiceImplMockTest
29+
- [[#7354](https://github.com/apache/incubator-seata/pull/7354)] fix the drivers in the libs folder cannot be loaded
2930
- [[#7356](https://github.com/apache/incubator-seata/pull/7356)] fix codecov bug
3031

3132

changes/zh-cn/2.x.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
### bugfix:
2828

2929
- [[#7349](https://github.com/apache/incubator-seata/pull/7349)] 解决 EtcdRegistryServiceImplMockTest 中的空指针异常
30+
- [[#7354](https://github.com/apache/incubator-seata/pull/7354)] 修复lib文件夹中的驱动程序无法加载
3031

3132
### optimize:
3233

core/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
*/
1717
package org.apache.seata.core.store.db;
1818

19+
import static org.apache.seata.common.DefaultValues.DEFAULT_DB_MAX_CONN;
20+
import static org.apache.seata.common.DefaultValues.DEFAULT_DB_MIN_CONN;
21+
1922
import java.io.File;
2023
import java.net.MalformedURLException;
2124
import java.net.URL;
@@ -24,9 +27,7 @@
2427
import java.util.Map;
2528
import java.util.Objects;
2629
import java.util.stream.Stream;
27-
2830
import javax.sql.DataSource;
29-
3031
import org.apache.seata.common.exception.ShouldNeverHappenException;
3132
import org.apache.seata.common.exception.StoreException;
3233
import org.apache.seata.common.executor.Initialize;
@@ -39,12 +40,9 @@
3940
import org.slf4j.Logger;
4041
import org.slf4j.LoggerFactory;
4142

42-
import static org.apache.seata.common.DefaultValues.DEFAULT_DB_MAX_CONN;
43-
import static org.apache.seata.common.DefaultValues.DEFAULT_DB_MIN_CONN;
44-
4543
/**
4644
* The abstract datasource provider
47-
*
45+
*
4846
*/
4947
public abstract class AbstractDataSourceProvider implements DataSourceProvider, Initialize {
5048

@@ -57,18 +55,18 @@ public abstract class AbstractDataSourceProvider implements DataSourceProvider,
5755
*/
5856
protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
5957

60-
private final static String MYSQL_DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";
58+
private static final String MYSQL_DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";
6159

62-
private final static String MYSQL8_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";
60+
private static final String MYSQL8_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";
6361

64-
private final static String MYSQL_DRIVER_FILE_PREFIX = "mysql-connector-j";
62+
private static final String MYSQL_DRIVER_FILE_PREFIX = "mysql-connector-j";
6563

66-
private final static Map<String, ClassLoader> MYSQL_DRIVER_LOADERS;
64+
private static final Map<String, ClassLoader> DRIVER_LOADERS;
6765

6866
private static final long DEFAULT_DB_MAX_WAIT = 5000;
6967

7068
static {
71-
MYSQL_DRIVER_LOADERS = createMysqlDriverClassLoaders();
69+
DRIVER_LOADERS = createMysqlDriverClassLoaders();
7270
}
7371

7472
@Override
@@ -87,7 +85,7 @@ public DataSource generate() {
8785
}
8886

8987
public void validate() {
90-
//valid driver class name
88+
// valid driver class name
9189
String driverClassName = getDriverClassName();
9290
ClassLoader loader = getDriverClassLoader();
9391
if (null == loader) {
@@ -106,14 +104,21 @@ public void validate() {
106104
.map(file -> file.isFile() ? file.getParentFile() : file)
107105
.filter(Objects::nonNull)
108106
.filter(File::isDirectory)
109-
.map(file -> new File(file, "jdbc"))
107+
// Only the MySQL driver needs to be placed in the jdbc folder.
108+
.map(file -> (MYSQL8_DRIVER_CLASS_NAME.equals(driverClassName)
109+
|| MYSQL_DRIVER_CLASS_NAME.equals(driverClassName))
110+
? new File(file, "jdbc")
111+
: file)
110112
.filter(File::exists)
111113
.filter(File::isDirectory)
112-
.distinct().findAny().orElseThrow(() -> new ShouldNeverHappenException("can not find jdbc folder")).getAbsolutePath();
114+
.distinct()
115+
.findAny()
116+
.map(File::getAbsolutePath)
117+
.orElseThrow(() -> new ShouldNeverHappenException("cannot find jdbc folder"));
113118
throw new StoreException(String.format(
114-
"The driver {%s} cannot be found in the path %s. Please ensure that the appropriate database driver dependencies are included in the classpath.", driverClassName, driverClassPath));
119+
"The driver {%s} cannot be found in the path %s. Please ensure that the appropriate database driver dependencies are included in the classpath.",
120+
driverClassName, driverClassPath));
115121
}
116-
117122
}
118123
/**
119124
* generate the datasource
@@ -139,7 +144,7 @@ protected String getDriverClassName() {
139144
String driverClassName = CONFIG.getConfig(ConfigurationKeys.STORE_DB_DRIVER_CLASS_NAME);
140145
if (StringUtils.isBlank(driverClassName)) {
141146
throw new StoreException(
142-
String.format("the {%s} can't be empty", ConfigurationKeys.STORE_DB_DRIVER_CLASS_NAME));
147+
String.format("the {%s} can't be empty", ConfigurationKeys.STORE_DB_DRIVER_CLASS_NAME));
143148
}
144149
return driverClassName;
145150
}
@@ -150,12 +155,12 @@ protected String getDriverClassName() {
150155
* @return the db max wait
151156
*/
152157
protected Long getMaxWait() {
153-
Long maxWait = CONFIG.getLong(ConfigurationKeys.STORE_DB_MAX_WAIT, DEFAULT_DB_MAX_WAIT);
154-
return maxWait;
158+
return CONFIG.getLong(ConfigurationKeys.STORE_DB_MAX_WAIT, DEFAULT_DB_MAX_WAIT);
155159
}
156160

157161
protected ClassLoader getDriverClassLoader() {
158-
return MYSQL_DRIVER_LOADERS.getOrDefault(getDriverClassName(), ClassLoader.getSystemClassLoader());
162+
return DRIVER_LOADERS.getOrDefault(
163+
getDriverClassName(), this.getClass().getClassLoader());
159164
}
160165

161166
private static Map<String, ClassLoader> createMysqlDriverClassLoaders() {
@@ -168,39 +173,39 @@ private static Map<String, ClassLoader> createMysqlDriverClassLoaders() {
168173
return loaders;
169174
}
170175
Stream.of(cp.split(File.pathSeparator))
171-
.map(File::new)
172-
.filter(File::exists)
173-
.map(file -> file.isFile() ? file.getParentFile() : file)
174-
.filter(Objects::nonNull)
175-
.filter(File::isDirectory)
176-
.map(file -> new File(file, "jdbc"))
177-
.filter(File::exists)
178-
.filter(File::isDirectory)
179-
.distinct()
180-
.flatMap(file -> {
181-
File[] files = file.listFiles((f, name) -> name.startsWith(MYSQL_DRIVER_FILE_PREFIX));
182-
if (files != null) {
183-
return Stream.of(files);
184-
} else {
185-
return Stream.of();
186-
}
187-
})
188-
.forEach(file -> {
189-
if (loaders.containsKey(MYSQL8_DRIVER_CLASS_NAME) && loaders.containsKey(MYSQL_DRIVER_CLASS_NAME)) {
190-
return;
191-
}
192-
try {
193-
URL url = file.toURI().toURL();
194-
ClassLoader loader = new URLClassLoader(new URL[]{url}, ClassLoader.getSystemClassLoader());
176+
.map(File::new)
177+
.filter(File::exists)
178+
.map(file -> file.isFile() ? file.getParentFile() : file)
179+
.filter(Objects::nonNull)
180+
.filter(File::isDirectory)
181+
.map(file -> new File(file, "jdbc"))
182+
.filter(File::exists)
183+
.filter(File::isDirectory)
184+
.distinct()
185+
.flatMap(file -> {
186+
File[] files = file.listFiles((f, name) -> name.startsWith(MYSQL_DRIVER_FILE_PREFIX));
187+
if (files != null) {
188+
return Stream.of(files);
189+
} else {
190+
return Stream.of();
191+
}
192+
})
193+
.forEach(file -> {
194+
if (loaders.containsKey(MYSQL8_DRIVER_CLASS_NAME) && loaders.containsKey(MYSQL_DRIVER_CLASS_NAME)) {
195+
return;
196+
}
195197
try {
196-
loader.loadClass(MYSQL8_DRIVER_CLASS_NAME);
197-
loaders.putIfAbsent(MYSQL8_DRIVER_CLASS_NAME, loader);
198-
} catch (ClassNotFoundException e) {
199-
loaders.putIfAbsent(MYSQL_DRIVER_CLASS_NAME, loader);
198+
URL url = file.toURI().toURL();
199+
ClassLoader loader = new URLClassLoader(new URL[] {url}, ClassLoader.getSystemClassLoader());
200+
try {
201+
loader.loadClass(MYSQL8_DRIVER_CLASS_NAME);
202+
loaders.putIfAbsent(MYSQL8_DRIVER_CLASS_NAME, loader);
203+
} catch (ClassNotFoundException e) {
204+
loaders.putIfAbsent(MYSQL_DRIVER_CLASS_NAME, loader);
205+
}
206+
} catch (MalformedURLException ignore) {
200207
}
201-
} catch (MalformedURLException ignore) {
202-
}
203-
});
208+
});
204209
return loaders;
205210
}
206211

@@ -243,8 +248,8 @@ protected String getPassword() {
243248
password = ConfigTools.publicDecrypt(password, publicKey);
244249
} catch (Exception e) {
245250
LOGGER.error(
246-
"decryption failed,please confirm whether the ciphertext and secret key are correct! error msg: {}",
247-
e.getMessage());
251+
"decryption failed,please confirm whether the ciphertext and secret key are correct! error msg: {}",
252+
e.getMessage());
248253
}
249254
}
250255
return password;
@@ -292,5 +297,4 @@ protected String getValidationQuery(DBType dbType) {
292297
protected String getPublicKey() {
293298
return CONFIG.getConfig(ConfigurationKeys.STORE_PUBLIC_KEY);
294299
}
295-
296300
}

server/src/main/java/org/apache/seata/server/store/DbcpDataSourceProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
import org.apache.seata.common.ConfigurationKeys;
2020
import org.apache.seata.common.loader.LoadLevel;
21-
import org.apache.seata.core.store.db.AbstractDataSourceProvider;
2221
import org.apache.commons.dbcp2.BasicDataSource;
22+
import org.apache.seata.core.store.db.AbstractDataSourceProvider;
2323

2424
import javax.sql.DataSource;
2525
import java.sql.Connection;

server/src/main/java/org/apache/seata/server/store/DruidDataSourceProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020

2121
import org.apache.seata.common.ConfigurationKeys;
2222
import org.apache.seata.common.loader.LoadLevel;
23-
import org.apache.seata.core.store.db.AbstractDataSourceProvider;
2423
import com.alibaba.druid.pool.DruidDataSource;
24+
import org.apache.seata.core.store.db.AbstractDataSourceProvider;
2525

2626
import java.sql.Connection;
2727

server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,27 @@
1919
import javax.sql.DataSource;
2020

2121
import org.apache.seata.common.loader.EnhancedServiceLoader;
22+
import org.apache.seata.common.loader.EnhancedServiceNotFoundException;
23+
import org.apache.seata.config.ConfigurationFactory;
2224
import org.apache.seata.core.store.db.DataSourceProvider;
25+
import org.apache.seata.server.lock.LockerManagerFactory;
26+
import org.apache.seata.server.session.SessionHolder;
27+
import org.junit.After;
28+
import org.junit.jupiter.api.AfterAll;
29+
import org.junit.jupiter.api.AfterEach;
2330
import org.junit.jupiter.api.Assertions;
31+
import org.junit.jupiter.api.BeforeAll;
32+
import org.junit.jupiter.api.MethodOrderer;
33+
import org.junit.jupiter.api.Order;
2434
import org.junit.jupiter.api.Test;
35+
import org.junit.jupiter.api.TestMethodOrder;
2536
import org.springframework.boot.test.context.SpringBootTest;
37+
import org.springframework.context.ApplicationContext;
2638

2739
/**
2840
*/
2941
@SpringBootTest
42+
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
3043
public class AbstractDataSourceProviderTest {
3144

3245
private final String dbcpDatasourceType = "dbcp";
@@ -36,29 +49,79 @@ public class AbstractDataSourceProviderTest {
3649
private final String hikariDatasourceType = "hikari";
3750

3851
private final String mysqlJdbcDriver = "com.mysql.jdbc.Driver";
52+
private final String mysql8JdbcDriver = "com.mysql.cj.jdbc.Driver";
53+
54+
@BeforeAll
55+
public static void setUp(ApplicationContext context) {
56+
EnhancedServiceLoader.unloadAll();
57+
ConfigurationFactory.reload();
58+
System.clearProperty("store.db.driverClassName");
59+
}
60+
61+
@AfterEach
62+
void tearDown() {
63+
EnhancedServiceLoader.unloadAll();
64+
ConfigurationFactory.reload();
65+
System.clearProperty("store.db.driverClassName");
66+
}
67+
3968

4069
@Test
70+
@Order(1)
4171
public void testDbcpDataSourceProvider() {
4272
DataSource dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbcpDatasourceType).provide();
4373
Assertions.assertNotNull(dataSource);
4474
}
4575

4676
@Test
77+
@Order(2)
78+
public void testLoadMysqlDriver() {
79+
System.setProperty("loader.path", "/tmp");
80+
System.setProperty("store.db.driverClassName", mysqlJdbcDriver);
81+
DataSource dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbcpDatasourceType).provide();
82+
Assertions.assertNotNull(dataSource);
83+
System.setProperty("store.db.driverClassName", mysql8JdbcDriver);
84+
dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbcpDatasourceType).provide();
85+
Assertions.assertNotNull(dataSource);
86+
}
87+
88+
@Test
89+
@Order(3)
90+
public void testLoadDMDriver() {
91+
System.setProperty("store.db.driverClassName", "dm.jdbc.driver.DmDriver");
92+
DataSource dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbcpDatasourceType).provide();
93+
Assertions.assertNotNull(dataSource);
94+
}
95+
96+
@Test
97+
@Order(4)
98+
public void testLoadDriverFailed() {
99+
System.setProperty("store.db.driverClassName", "dm.jdbc.driver.DmDriver1");
100+
Assertions.assertThrows(EnhancedServiceNotFoundException.class, () -> {
101+
EnhancedServiceLoader.load(DataSourceProvider.class, dbcpDatasourceType).provide();
102+
});
103+
}
104+
105+
@Test
106+
@Order(5)
47107
public void testDruidDataSourceProvider() {
48108
DataSource dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, druidDatasourceType).provide();
49109
Assertions.assertNotNull(dataSource);
50110
}
51111

52112
@Test
113+
@Order(6)
53114
public void testHikariDataSourceProvider() {
54115
DataSource dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, hikariDatasourceType).provide();
55116
Assertions.assertNotNull(dataSource);
56117
}
57118

58119
@Test
120+
@Order(7)
59121
public void testMySQLDataSourceProvider() throws ClassNotFoundException {
60122
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
61123
Class<?> driverClass = Class.forName(mysqlJdbcDriver, true, classLoader);
62124
Assertions.assertNotNull(driverClass);
63125
}
126+
64127
}

0 commit comments

Comments
 (0)