日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

类加载器-线程上下文

發布時間:2024/4/13 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 类加载器-线程上下文 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

線程上下文類加載器

我們在使用 JDBC 時,都需要加載 Driver 驅動,不知道你注意到沒有,不寫

Class.forName("com.mysql.jdbc.Driver")

也是可以讓 com.mysql.jdbc.Driver 正確加載的,你知道是怎么做的嗎?

讓我們追蹤一下源碼:

public class DriverManager {// 注冊驅動的集合private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers= new CopyOnWriteArrayList<>();// 初始化驅動static {loadInitialDrivers();println("JDBC DriverManager initialized");} }

先不看別的,看看 DriverManager 的類加載器:

System.out.println(DriverManager.class.getClassLoader());

打印 null,表示它的類加載器是 Bootstrap ClassLoader,會到 JAVA_HOME/jre/lib 下搜索類,但JAVA_HOME/jre/lib 下顯然沒有 mysql-connector-java-5.1.47.jar 包,這樣問題來了,在DriverManager 的靜態代碼塊中,怎么能正確加載 com.mysql.jdbc.Driver 呢?

繼續看 loadInitialDrivers() 方法:

private static void loadInitialDrivers() {String drivers;try {drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {public String run() {return System.getProperty("jdbc.drivers");}});} catch (Exception ex) {drivers = null;}public Void run() {ServiceLoader<Driver> loadedDrivers =ServiceLoader.load(Driver.class);Iterator<Driver> driversIterator = loadedDrivers.iterator();try{while(driversIterator.hasNext()) {driversIterator.next();}catch(Throwable t) {// Do nothing}return null;} } println("DriverManager.initialize: jdbc.drivers = " + drivers); // 2)使用 jdbc.drivers 定義的驅動名加載驅動 if (drivers == null || drivers.equals("")) {return; } String[] driversList = drivers.split(":"); println("number of Drivers:" + driversList.length); for (String aDriver : driversList) {try {println("DriverManager.Initialize: loading " + aDriver);// 這里的 ClassLoader.getSystemClassLoader() 就是應用程序類加載器Class.forName(aDriver, true,ClassLoader.getSystemClassLoader());} catch (Exception ex) {println("DriverManager.Initialize: load failed: " + ex);} }

先看 2)發現它最后是使用 Class.forName 完成類的加載和初始化,關聯的是應用程序類加載器,因此可以順利完成類加載

再看 1)它就是大名鼎鼎的 Service Provider Interface (SPI)

約定如下,在 jar 包的 META-INF/services 包下,以接口全限定名名為文件,文件內容是實現類名稱

這樣就可以使用

ServiceLoader<接口類型> allImpls = ServiceLoader.load(接口類型.class); Iterator<接口類型> iter = allImpls.iterator(); while(iter.hasNext()) {iter.next(); }

來得到實現類,體現的是【面向接口編程+解耦】的思想,在下面一些框架中都運用了此思想:
?? ?JDBC
?? ?Servlet 初始化器
?? ?Spring 容器
?? ?Dubbo(對 SPI 進行了擴展)

接著看 ServiceLoader.load 方法:

public static <S> ServiceLoader<S> load(Class<S> service) {// 獲取線程上下文類加載器ClassLoader cl = Thread.currentThread().getContextClassLoader();return ServiceLoader.load(service, cl); }

線程上下文類加載器是當前線程使用的類加載器,默認就是應用程序類加載器,它內部又是由Class.forName 調用了線程上下文類加載器完成類加載,具體代碼在 ServiceLoader 的內部類LazyIterator 中:

private S nextService() {if (!hasNextService())throw new NoSuchElementException();String cn = nextName;nextName = null;Class<?> c = null;try {c = Class.forName(cn, false, loader);} catch (ClassNotFoundException x) {fail(service,if (!service.isAssignableFrom(c)) {fail(service,"Provider " + cn + " not a subtype");}try {S p = service.cast(c.newInstance());providers.put(cn, p);return p;} catch (Throwable x) {fail(service,"Provider " + cn + " could not be instantiated",x);}throw new Error(); // This cannot happen} }

?

總結

以上是生活随笔為你收集整理的类加载器-线程上下文的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。