打印Thread.currentThread().getContextClassLoader(),显示如下:
sun.misc.Launcher$AppClassLoader@19821f
这个加载器是系统类加载器。ClassLoader.getSystemResourceAsStream("com/config.xml")使用的就是系统类加载器定位资源的。
java中共有三种类型的类加载器:
1、引导(bootstrap)类加载器(用来加载java API类),例如加载java.lang.String类
2、扩展类加载器(就是sun.misc.Launcher$ExtClassLoader,用来加载jre\lib\ext目录下的jar包)
3、系统类加载器(就是sun.misc.Launcher$AppClassLoader,主要用来加载CLASSPATH设置目录中的Class)
创建一个URLClassLoader,发现其父加载器(parent,注意不是父类)的类型为sun.misc.Launcher$AppClassLoader,而sun.misc.Launcher$AppClassLoader和sun.misc.Launcher$ExtClassLoader的父类都是URLClassLoader。AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器为null,即bootstrap类加载器。
类加载有个双亲委托模式,
AppClassLoader的父加载器是ExtClassLoader ,ExtClassLoader 的父加载器是bootstrap classloader,bootstrap 是C++写的类加载器,会负责加载java核心类库,就是jre/lib/rt.jar
ExtClassLoader会加载扩展类库,就是jre/lib/ext下的库。
双亲委托模式就是子加载器会先委托父加载器加载,父加载器加载不了子加载器才加载,
这样做避免了重复加载,也加强了java的安全了,防止了恶意加载器去加载核心库。
注意:
1,在类A中使用Class.forName加载类B,那么加载类A的类加载器将会用于加载类B,这样两个类的类加载器是同一个。
2,Class.forName("")和classLoader.load("")的区别主要是前者会做初始化,后者不会。见jdk注释: A call to forName("X") causes the class named X to be initialized. 自己分别用两种方式装载一个带静态代码的类就知道了。jdbc需要通过Class.forName("")的方式来装载JDBC驱动程序(例如 Class.forName("com.mysql.jdbc.Driver"),之所以用Class.forName而没有用 ClassLoader.load(),就是因为需要JVM完成Driver的初始化工作,而不仅仅是装载),然后通过一个统一的工厂类 Java.sql.DriverManager来取得数据库连接,并执行各种操作。 Class.forName("")不仅load class而且还保证resolve这个class,包括常量池解析,类初始化。。。这样JDBC驱动使用这个方法,才能保证类里的静态方法执行,一般驱动类的静态方法会向DriverManager注册自己,如果用classloader.load("")就不一定会resolve这个class,也就不能保证注册驱动类!
看了com.mysql.jdbc.Driver类的源码,静态代码就一句:java.sql.DriverManager.registerDriver(new com.mysql.jdbc.Driver())
3,
参考
1)java系统类加载器AppClassLoader之浅谈 http://blog.sina.com.cn/s/blog_4db6a3f101000do1.html
2)java类加载原理分析 http://gongmingwind.javaeye.com/blog/338366
3)解读ClassLoader http://www.javaeye.com/topic/83978
4)http://xyiyy.javaeye.com/blog/362107
Retrotranslator是一个Java字节码转换工具。它能够把用JDK5.0编译的Java Class转换成可运行在JVM1.4
sun.misc.Launcher$AppClassLoader@19821f
这个加载器是系统类加载器。ClassLoader.getSystemResourceAsStream("com/config.xml")使用的就是系统类加载器定位资源的。
//JDK1.6,java.lang.ClassLoader的
loadClass(String name,
boolean
resolve)方法的源码
protected synchronized Class <?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null ) {
try {
if (parent != null ) {
// 如果parent不为null,则调用parent的loadClass进行加载
c = parent.loadClass(name, false );
} else {
// parent为null,则调用BootstrapClassLoader进行加载
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.
// 如果仍然无法加载成功,则调用自身的findClass进行加载
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
protected synchronized Class <?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null ) {
try {
if (parent != null ) {
// 如果parent不为null,则调用parent的loadClass进行加载
c = parent.loadClass(name, false );
} else {
// parent为null,则调用BootstrapClassLoader进行加载
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.
// 如果仍然无法加载成功,则调用自身的findClass进行加载
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
java中共有三种类型的类加载器:
1、引导(bootstrap)类加载器(用来加载java API类),例如加载java.lang.String类
2、扩展类加载器(就是sun.misc.Launcher$ExtClassLoader,用来加载jre\lib\ext目录下的jar包)
3、系统类加载器(就是sun.misc.Launcher$AppClassLoader,主要用来加载CLASSPATH设置目录中的Class)
创建一个URLClassLoader,发现其父加载器(parent,注意不是父类)的类型为sun.misc.Launcher$AppClassLoader,而sun.misc.Launcher$AppClassLoader和sun.misc.Launcher$ExtClassLoader的父类都是URLClassLoader。AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器为null,即bootstrap类加载器。
类加载有个双亲委托模式,
AppClassLoader的父加载器是ExtClassLoader ,ExtClassLoader 的父加载器是bootstrap classloader,bootstrap 是C++写的类加载器,会负责加载java核心类库,就是jre/lib/rt.jar
ExtClassLoader会加载扩展类库,就是jre/lib/ext下的库。
双亲委托模式就是子加载器会先委托父加载器加载,父加载器加载不了子加载器才加载,
这样做避免了重复加载,也加强了java的安全了,防止了恶意加载器去加载核心库。
String name
=
"
com.domain.Account
"
;
URL url1 = new URL( " file:/D:/workspace/test/bin/ " );
ClassLoader cl = new URLClassLoader( new URL[] { url1 });
Class c1 = cl.loadClass(name);
URL url2 = new URL( " file:/D:/workspace/test/bin " );
ClassLoader cl2 = new URLClassLoader( new URL[] { url2 });
Class c2 = cl2.loadClass(name);
System.out.println(c1 == c2); // 返回true,原因是都是用系统类加载器AppClassLoader 加载的
URL url1 = new URL( " file:/D:/workspace/test/bin/ " );
ClassLoader cl = new URLClassLoader( new URL[] { url1 });
Class c1 = cl.loadClass(name);
URL url2 = new URL( " file:/D:/workspace/test/bin " );
ClassLoader cl2 = new URLClassLoader( new URL[] { url2 });
Class c2 = cl2.loadClass(name);
System.out.println(c1 == c2); // 返回true,原因是都是用系统类加载器AppClassLoader 加载的
注意:
1,在类A中使用Class.forName加载类B,那么加载类A的类加载器将会用于加载类B,这样两个类的类加载器是同一个。
2,Class.forName("")和classLoader.load("")的区别主要是前者会做初始化,后者不会。见jdk注释: A call to forName("X") causes the class named X to be initialized. 自己分别用两种方式装载一个带静态代码的类就知道了。jdbc需要通过Class.forName("")的方式来装载JDBC驱动程序(例如 Class.forName("com.mysql.jdbc.Driver"),之所以用Class.forName而没有用 ClassLoader.load(),就是因为需要JVM完成Driver的初始化工作,而不仅仅是装载),然后通过一个统一的工厂类 Java.sql.DriverManager来取得数据库连接,并执行各种操作。 Class.forName("")不仅load class而且还保证resolve这个class,包括常量池解析,类初始化。。。这样JDBC驱动使用这个方法,才能保证类里的静态方法执行,一般驱动类的静态方法会向DriverManager注册自己,如果用classloader.load("")就不一定会resolve这个class,也就不能保证注册驱动类!
看了com.mysql.jdbc.Driver类的源码,静态代码就一句:java.sql.DriverManager.registerDriver(new com.mysql.jdbc.Driver())
3,
参考
1)java系统类加载器AppClassLoader之浅谈 http://blog.sina.com.cn/s/blog_4db6a3f101000do1.html
2)java类加载原理分析 http://gongmingwind.javaeye.com/blog/338366
3)解读ClassLoader http://www.javaeye.com/topic/83978
4)http://xyiyy.javaeye.com/blog/362107
Retrotranslator是一个Java字节码转换工具。它能够把用JDK5.0编译的Java Class转换成可运行在JVM1.4