flink 類載入剖析

耗子哥信徒發表於2024-11-03
Caused by: java.sql.SQLException: No suitable driver found for jdbc:mysql://25.79.1.13:90/tide_cloud?connectTimeout=60000&socketTimeout=60000
        at java.sql.DriverManager.getConnection(DriverManager.java:689) ~[?:1.8.0_332]
        at java.sql.DriverManager.getConnection(DriverManager.java:247) ~[?:1.8.0_332]
        at org.apache.flink.connector.jdbc.catalog.MySqlCatalog.getDriverVersion(MySqlCatalog.java:159) ~[?:?]
        at org.apache.flink.connector.jdbc.catalog.MySqlCatalog.<init>(MySqlCatalog.java:93) ~[?:?]
        at com.tide.util.TableAssembler.build(TableAssembler.java:63) ~[?:?]
        at com.tide.Insight.prepare(Insight.java:112) ~[?:?]
        at com.tide.Insight.execute(Insight.java:104) ~[?:?]
        at com.tide.Insight.main(Insight.java:48) ~[?:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_332]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_332]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_332]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_332]
        at org.apache.flink.client.program.PackagedProgram.callMainMethod(PackagedProgram.java:355) ~[flink-dist-1.17.1.jar:1.17.1]
        ... 7 more
public void invokeInteractiveModeForExecution() throws ProgramInvocationException {
        FlinkSecurityManager.monitorUserSystemExitForCurrentThread();
        try {
            callMainMethod(mainClass, args);
        } finally {
            FlinkSecurityManager.unmonitorUserSystemExitForCurrentThread();
        }
    }
 this.mainClass =
                loadMainClass(
                        // if no entryPointClassName name was given, we try and look one up through
                        // the manifest
                        entryPointClassName != null
                                ? entryPointClassName
                                : getEntryPointClassNameFromJar(this.jarFile),
                        userCodeClassLoader);

mainClass是 ChildFirstClassLoader載入的,因此java.sql.DriverManager.getConnection也是ChildFirstClassLoader載入的。

因此,

//        log.info(java.sql.DriverManager.class.getClassLoader().toString());
 log.info(Insight.class.getClassLoader().toString());
 log.info(com.mysql.cj.jdbc.Driver.class.getClassLoader().toString());

輸出:

org.apache.flink.util.ChildFirstClassLoader@7d81f8b6
sun.misc.Launcher$AppClassLoader@12a3a380

ChildFirstClassLoader 是 Flink 自定義的類載入器,繼承自 Java 的 ClassLoader 類,但它的工作機制和 AppClassLoader 不同。
ChildFirstClassLoader 會將子類載入器的類優先載入,而 AppClassLoader 則是按照預設的父類優先載入機制工作。
這兩者之間並沒有直接的繼承關係或父子關係,而是獨立存在的,用於不同的目的和場景。

去掉classloader.parent-first-patterns.additional: com.mysql.; org.codehaus.配置之後,
列印:

org.apache.flink.util.ChildFirstClassLoader@69cebb68
org.apache.flink.util.ChildFirstClassLoader@69cebb68

這時候抱錯了,提示No suitable driver found for jdbc,猜測原因:

  • java.sql.DriverManager是由Boostrap類載入器載入的
  • com.mysql.cj.jdbc.Driver 是由ChildFirstClassLoader類載入器載入的。

https://juejin.cn/post/7249934982114672695

知識點

1、任意一個類,都需要由載入它的類載入器和這個類本身一同確立其在Java虛擬機器中的唯一性,每一個類載入器,都擁有一個獨立的類名稱空間。這句話可以表達更通俗一些:比較兩個類是否”相等”,只有再這兩個類是有同一個類載入器載入的前提下才有意義,否則,即使這兩個類來源於同一個Class 檔案,被同一個虛擬機器載入,只要載入它們的類載入器不同,那這兩個類就必定不相等。

2、類載入器本身不存在繼承關係。 即使有雙親委派關係的存在,一個類的載入器,指的也是實際載入這個類的classLoader

3、每個執行緒繫結一個classLoader

相關文章