亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

一。類加載器及雙親委派機(jī)制

 

Java 類加載機(jī)制詳解

Java 類加載機(jī)制詳解

1. 類加載器繼承結(jié)構(gòu)

Java 類加載機(jī)制詳解

Java 類加載機(jī)制詳解

2. 類加載器的核心方法

Java 類加載機(jī)制詳解

?3. Launcher 類源碼解析

public class Launcher {

private static URLStreamHandlerFactory factory = new Factory();

private static Launcher launcher = new Launcher();

// 啟動(dòng)類加載器加載路徑

private static String bootClassPath =

System.getProperty("sun.boot.class.path");

public static Launcher getLauncher() {

return launcher;

}

private ClassLoader loader;

public Launcher() {

// Create the extension class loader

ClassLoader extcl;

try {

// 獲取擴(kuò)展類加載器

extcl = ExtClassLoader.getExtClassLoader();

} catch (IOException e) {

throw new InternalError(

"Could not create extension class loader", e);

}

// Now create the class loader to use to launch the Application

try {

// 獲取應(yīng)用類加載器

loader = AppClassLoader.getAppClassLoader(extcl);

} catch (IOException e) {

throw new InternalError(

"Could not create application class loader", e);

}

// Also set the context class loader for the primordial thread.

// 設(shè)置線程上下文類加載器為應(yīng)用類加載器

Thread.currentThread().setContextClassLoader(loader);

}

/*

* The class loader used for loading installed extensions.

*/

static class ExtClassLoader extends URLClassLoader {

private static volatile ExtClassLoader instance = null;

/**

* create an ExtClassLoader. The ExtClassLoader is created

* within a context that limits which files it can read

*/

public static ExtClassLoader getExtClassLoader() throws IOException

{

if (instance == null) {

synchronized(ExtClassLoader.class) {

if (instance == null) {

instance = createExtClassLoader();

}

}

}

return instance;

}

/**

* 獲取加載路徑

*/

private static File[] getExtDirs() {

// 擴(kuò)展類加載器加載路徑

String s = System.getProperty("JAVA.ext.dirs");

}

}

/**

* The class loader used for loading from java.class.path.

* runs in a restricted security context.

*/

static class AppClassLoader extends URLClassLoader {

public static ClassLoader getAppClassLoader(final ClassLoader extcl)

throws IOException

{

// 應(yīng)用類加載器加載路徑

final String s = System.getProperty("java.class.path");

final File[] path = (s == null) ? new File[0] : getClassPath(s);

return AccessController.doPrivileged(

new PrivilegedAction<AppClassLoader>() {

public AppClassLoader run() {

URL[] urls =

(s == null) ? new URL[0] : pathToURLs(path);

return new AppClassLoader(urls, extcl);

}

});

}

}

?4. ClassLoader 類源碼解析

public abstract class ClassLoader {

protected Class<?> loadClass(String name, boolean resolve)

throws ClassNotFoundException

{

synchronized (getClassLoadingLock(name)) {

// First, check if the class has already been loaded

// 從系統(tǒng)緩存中獲取

Class<?> c = findLoadedClass(name);

if (c == null) {

long t0 = System.nanoTime();

try {

// 委托父加載器加載

if (parent != null) {

c = parent.loadClass(name, false);

} else {

c = findBootstrapClassOrNull(name);

}

} catch (ClassNotFoundException e) {

// ClassNotFoundException thrown if class not found

// from the non-null parent class loader

}

if (c == null) {

// If still not found, then invoke findClass in order

// to find the class.

long t1 = System.nanoTime();

// 自己加載,從指定路徑

c = findClass(name);

// this is the defining class loader; record the stats

sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);

sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);

sun.misc.PerfCounter.getFindClasses().increment();

}

}

if (resolve) {

resolveClass(c);

}

return c;

}

}

// 自定義類加載器需要重寫該方法

protected Class<?> findClass(String name) throws ClassNotFoundException {

throw new ClassNotFoundException(name);

}

}

5. 雙親委派機(jī)制優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1、保證安全性,層級(jí)關(guān)系代表優(yōu)先級(jí),也就是所有類的加載,優(yōu)先給啟動(dòng)類加載器,這樣就保證了核心類庫類

2、避免類的重復(fù)加載,如果父類加載器加載過了,子類加載器就沒有必要再去加載了,確保一個(gè)類的全局唯一性

缺點(diǎn):

檢查類是否加載的委派過程是單向的, 這個(gè)方式雖然從結(jié)構(gòu)上說比較清晰,使各個(gè) ClassLoader 的職責(zé)非常明確, 但是同時(shí)會(huì)帶來一個(gè)問題, 即頂層的 ClassLoader 無法訪問底層的 ClassLoader 所加載的類

通常情況下, 啟動(dòng)類加載器中的類為系統(tǒng)核心類, 包括一些重要的系統(tǒng)接口,而在應(yīng)用類加載器中, 為應(yīng)用類。 按照這種模式, 應(yīng)用類訪問系統(tǒng)類自然是沒有問題, 但是系統(tǒng)類訪問應(yīng)用類就會(huì)出現(xiàn)問題。

二.spi 接口及線程上下文類加載器

1.spi 接口定義及線程上下文加載的作用

Java 提供了很多核心接口的定義,這些接口被稱為 SPI 接口。(Service Provider Interface,SPI),允許第三方為這些接口提供實(shí)現(xiàn)。常見的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。

這些 SPI 的接口由 Java 核心庫來提供,而這些 SPI 的實(shí)現(xiàn)代碼則是作為 Java 應(yīng)用所依賴的 jar 包被包含進(jìn)類路徑(CLASSPATH)里。SPI 接口中的代碼經(jīng)常需要加載具體的實(shí)現(xiàn)類。那么問題來了,SPI 的接口是 Java 核心庫的一部分,是由啟動(dòng)類加載器 (Bootstrap Classloader) 來加載的;SPI 的實(shí)現(xiàn)類是由系統(tǒng)類加載器 (System ClassLoader) 來加載的。引導(dǎo)類加載器是無法找到 SPI 的實(shí)現(xiàn)類的,因?yàn)橐勒针p親委派模型,BootstrapClassloader 無法委派 AppClassLoader 來加載類。而線程上下文類加載器破壞了 “雙親委派模型”,可以在執(zhí)行線程中拋棄雙親委派加載鏈模式,使程序可以逆向使用類加載器。

類加載傳導(dǎo)規(guī)則:JVM 會(huì)選擇當(dāng)前類的類加載器來加載所有該類的引用的類。例如我們定義了 TestA 和 TestB 兩個(gè)類,TestA 會(huì)引用 TestB,只要我們使用自定義的類加載器加載 TestA,那么在運(yùn)行時(shí),當(dāng) TestA 調(diào)用到 TestB 的時(shí)候,

TestB 也會(huì)被 JVM 使用 TestA 的類加載器加載。依此類推,只要是 TestA 及其引用類關(guān)聯(lián)的所有 jar 包的類都會(huì)被自定義類加載器加載。通過這種方式,我們只要讓模塊的 mAIn 方法類使用不同的類加載器加載,那么每個(gè)模塊的都會(huì)使用 main

方法類的類加載器加載的,這樣就能讓多個(gè)模塊分別使用不同類加載器。這也是 OSGi 和 SofaArk 能夠?qū)崿F(xiàn)類隔離的核心原理。

2. spi 加載原理

當(dāng)?shù)谌綄?shí)現(xiàn)者提供了服務(wù)接口的一種實(shí)現(xiàn)之后,在 jar 包的 META-INF/services/ 目錄里同時(shí)創(chuàng)建一個(gè)以服務(wù)接口命名的文件,該文件就是實(shí)現(xiàn)該服務(wù)接口的實(shí)現(xiàn)類。而當(dāng)外部程序裝配這個(gè)模塊的時(shí)候,就能通過該 jar 包 META-INF/services/ 里的配置文件找到具體的實(shí)現(xiàn)類名,并裝載實(shí)例化,完成模塊的注入。

JDK 官方提供了一個(gè)查找服務(wù)實(shí)現(xiàn)者的工具類:java.util.ServiceLoader

public final class ServiceLoader<S>

implements Iterable<S>

{

// 加載spi接口實(shí)現(xiàn)類配置文件固定路徑

private static final String PREFIX = "META-INF/services/";

/**

* Creates a new service loader for the given service type, using the

* current thread's {@linkplain java.lang.Thread#getContextClassLoader

* context class loader}.

* <p> An invocation of this convenience method of the form

* <blockquote><pre>

* ServiceLoader.load(<i>service</i>)</pre></blockquote>

* is equivalent to

* <blockquote><pre>

* ServiceLoader.load(<i>service</i>,

* Thread.currentThread().getContextClassLoader())</pre></blockquote>

* @param <S> the class of the service type

* @param service

* The interface or abstract class representing the service

* @return A new service loader

*/

public static <S> ServiceLoader<S> load(Class<S> service) {

// 線程上下文類加載器

ClassLoader cl = Thread.currentThread().getContextClassLoader();

return ServiceLoader.load(service, cl);

}

}

?3. 示列代碼

代碼:

public interface IShout {

void shout();

}

public class Dog implements IShout {

@Override

public void shout() {

System.out.println("wang wang");

}

}

public class Cat implements IShout {

@Override

public void shout() {

System.out.println("miao miao");

}

}

public class Main {

public static void main(String[] args) {

ServiceLoader<IShout> shouts = ServiceLoader.load(IShout.class);

for (IShout s : shouts) {

s.shout();

}

}

}

配置:

Java 類加載機(jī)制詳解

??4.MySQL 驅(qū)動(dòng)類加載

Java 類加載機(jī)制詳解

// 加載Class到AppClassLoader(系統(tǒng)類加載器),然后注冊驅(qū)動(dòng)類

//Class.forName("com.mysql.jdbc.Driver").newInstance();

String url = "jdbc:mysql://localhost:3306/testdb";

// 通過java庫獲取數(shù)據(jù)庫連接

Connection conn = java.sql.DriverManager.getConnection(url, "name", "password");

public class DriverManager {

static {

loadInitialDrivers();

println("JDBC DriverManager initialized");

}

private static void loadInitialDrivers() {

。。。。。。。

AccessController.doPrivileged(new PrivilegedAction<Void>() {

public Void run() {

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);

Iterator<Driver> driversIterator = loadedDrivers.iterator();

/* Load these drivers, so that they can be instantiated.

* It may be the case that the driver class may not be there

* i.e. there may be a packaged driver with the service class

* as implementation of java.sql.Driver but the actual class

* may be missing. In that case a java.util.ServiceConfigurati

* will be thrown at runtime by the VM trying to locate

* and load the service.

* Adding a try catch block to catch those runtime errors

* if driver not available in classpath but it's

* packaged as service and that service is there in classpath.

*/

try{

while(driversIterator.hasNext()) {

driversIterator.next();

}

} catch(Throwable t) {

// Do nothing

}

return null;

}

});

println("DriverManager.initialize: jdbc.drivers = " + 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);

Class.forName(aDriver, true,

ClassLoader.getSystemClassLoader());

} catch (Exception ex) {

println("DriverManager.Initialize: load failed: " + ex);

}

}

}

}

三。自定義動(dòng)態(tài)類加載器

1. 示例代碼

public class DynamicClassLoad extends ClassLoader{

public static void main(String[] args) {

Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {

@Override

public void run() {

try {

DynamicClassLoad myClassLoad = new DynamicClassLoad();

Class clazz = myClassLoad.findClass("/Users/wangzhaoqing1/Desktop/MyTest.class");

Object obj = clazz.newInstance();

Method sayHello = clazz.getDeclaredMethod("sayHello");

sayHello.invoke(obj, null);

} catch (Throwable e) {

e.printStackTrace();

}

}

}, 1, 2, TimeUnit.SECONDS);

}

@Override

protected Class<?> findClass(String name) throws ClassNotFoundException {

File file = new File(name);

try {

byte[] bytes = FileUtils.readFileToByteArray(file);

Class<?> c = this.defineClass(null, bytes, 0, bytes.length);

return c;

} catch (Exception e) {

e.printStackTrace();

}

return super.findClass(name);

}

}

// DynamicClassLoad啟動(dòng)后,修改本類重新編譯

public class MyTest {

public void sayHello(){

System.out.println("hello wzq 6666666666");

}

}

 

作者:京東零售 王照清
來源:京東云開發(fā)者社區(qū) 轉(zhuǎn)載請注明來源

分享到:
標(biāo)簽:Java
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定