天天看點

ClassLoader 解決問題的一次小思考

ClassLoader的一次小了解

      • 背景
      • 探索解決

背景

今天群裡一哥們說了一個問題,試了好幾下才解決。有點慚愧,記錄之。

需求:

業務方要求,需要通路sqlite資料庫,但是不能提前把sqlite的jar包放到工程裡。( 可能是為了實作技術上的所謂的熱拔插吧)

探索解決

需求是否合理,到了開發解決,隻有使命必達。

當然,前提是有可行性,否則你可以拿着40米的大刀,讓需求側同學先跑39米 :))

熱拔插,那就拿出反射來搞一把呗。

于是乎,有了一下過程

  • 第一版代碼
String path ="file:///User/xx/tmp/sqlite-jdbc-3.8.7.jar";
            URL url = new URL(path);
            URLClassLoader myClassLoader = new URLClassLoader(new URL[] {url},Thread.currentThread()
                    .getContextClassLoader());
            Class<?> driverClass = myClassLoader.loadClass("org.sqlite.JDBC");
            Class.forName("org.sqlite.JDBC",true, myClassLoader);


            String dbURL="jdbc:sqlite:C:/Users/Administrator/Downloads/test.db";

            Class<?> dmClazz = myClassLoader.loadClass("java.sql.DriverManager");
            Method method = dmClazz.getMethod("getConnection", Connection.class);
            Connection conn  = (Connection)method.invoke(null,dbURL);
           

以上代碼用了反射,類加載器,指導思想是,既然是動态加載,那就全部用新的classload 搞進來,不就可以了嗎?

結果,不行。 因為DriverManager getConnection 是個靜态方法,而且沒有給你指定loader的地方。 即使自己load近來,依然找不到驅動。

  • 思考總結

上述代碼,把已經想到的構造一個classloader 反射調用方法,擷取Connection,都用了,發現還是不行。

此時,喝杯茶,靜一下。

翻看一下代碼

Class.forName();
DriverManager.getConnection
           

看了一下相關注釋,JDBC本身就是用反射擷取驅動類,進行管理。

是以這時,思考了一下,是否換個思路,把驅動jar包放到目前loader的classpath即可。

  • 解決方案

指導思想:

1.擷取目前loader

2.擷取相關jar包

3.放進目前loader對應的classpath

代碼如下:

//1.擷取jar
			String path ="file:///User/xx/tmp/sqlite-jdbc-3.8.7.jar";
            URL url = new URL(path);
            //2擷取目前loader
            URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
			//3. 把外部臨時加載的jar包放進classpath
            Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            boolean accessible=method.isAccessible();
            method.setAccessible(true);
            
            method.invoke(classLoader, url);
            
            method.setAccessible(accessible);
           
  • 小結

回顧解決問題的過程,其實剛開始受問題發起者的影響較大,繞進了技術範疇。

遇阻後,倒過來根據經驗解決問題,反倒立馬解決

很多時間,不是技術問題,是經驗問題