- 浏览: 284891 次
- 性别:
- 来自: 南昌
文章分类
- 全部博客 (196)
- HTML (4)
- ubuntu (4)
- maven (4)
- JAVA (5)
- mysql (5)
- TOMCAT (2)
- velocity (1)
- JSP (1)
- Eclipse (4)
- jetspeed (3)
- android (1)
- jquery (4)
- 行业应用 (2)
- fastjson (2)
- gfg (0)
- Log4j (1)
- tree (1)
- javascript (6)
- IE (3)
- image (2)
- Derby (1)
- axis2 (1)
- myeclipse (1)
- TCP/IP (1)
- struts2 (2)
- jbpm (1)
- jsonp (1)
- apache+tomcat (1)
- dwr (2)
- XML解析 (1)
- keyCode (1)
- CSS (6)
- spring (1)
- SQL (1)
- JSON (1)
- freemarker (0)
- memcache (1)
最新评论
-
seraph_fd:
好厉害的样子。 最近用手拼 SQL 句子做了很多东西,现在要统 ...
Java防止SQL注入的几个途径 -
一叶一菩提:
你考虑过 in 吗?
preparedstatement不支 ...
Java防止SQL注入的几个途径 -
顽固的卡夫卡:
time per request (mean): 单个请求响应 ...
开源性能测试工具 - Apache ab 介绍 -
helloklzs:
主要是根据你自己的电脑配置来相应调整合适大小的
eclipse Failed to create the Java Virtual Machine -
kobe1029:
为什么要这么设置??????
eclipse Failed to create the Java Virtual Machine
参考文章:
http://blog.csdn.net/lovingprince/archive/2009/06/03/4238695.aspx
http://www.yesky.com/243/1840743.shtml
http://blog.csdn.net/gtuu0123/article/details/4493757
Java为了提供平台无关性,在操作系统之上加入了一层JVM来隔离操作系统特定实现,使所编写的java代码在任何平台都能运行,但是JVM是特定于某一操作系统的
一、当JVM启动时,由三个类加载器对类进行加载:
1.bootstrap classloader
2.extension classloader
3.system classloader
(1)bootstrap classloader[ 引导类加载器] 是由JVM实现的,不是java.lang.ClassLoader的子类 ,它负责加载Java的核心类,其加载的类由 sun.boot.class.path指定,或者在 执行java命令时使用-Xbootclasspath选项或使用-D选项指定sun.boot.class.path系统属性值
说明:
-Dproperty_name=property_value 指定属性的值;
-Xbootclasspath 改变虚拟机装载缺省系统运行包rt.jar,而从-Xbootclasspath中设定的搜索路径中装载系统运行类
输出加载的核心类库:
view plaincopy to clipboardprint?
01.public class TestBootstrapClassLoader {
02. public static void main(String[] args) {
03. URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
04. for (int i = 0; i < urls.length; i++) {
05. System.out.println(urls[i].toExternalForm());
06. }
07. }
08.}
public class TestBootstrapClassLoader {
public static void main(String[] args) {
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
}
}
输出结果:
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/rt.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/i18n.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/sunrsasign.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/jsse.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/jce.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/charsets.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/classes
(2) extension classloader[扩展类加载器] ,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。这为引入除Java核心类以外的新功能提供了一个标准机制。在这个实例上调用方法getParent()总是返回空值null,因为引导加载器bootstrap classloader不是一个真正的ClassLoader实例。
view plaincopy to clipboardprint?
01.class TestExtensionClassLoader {
02. public static void main(String[] args) {
03. System.out.println(System.getProperty("java.ext.dirs"));
04. ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
05. System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
06. }
07.}
class TestExtensionClassLoader {
public static void main(String[] args) {
System.out.println(System.getProperty("java.ext.dirs"));
ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
}
}
输出结果:
E:/MyEclipse 5.1.1 GA/jre/lib/ext
the parent of extension classloader : null
以上这段代码也表明了下列父子关系或加载顺序:
bootstrap classloader(因其不是ClassLoader的子类,null)-->extension classloader-->system classloader
这也表明了jvm在加载类的顺序,当加载一个类时(假设其未加载),先找到最顶层的classloader,如果其可以加载这个类(或者已经加载了这个类),则返回这个类;如果其不能加载类(换个说法:在相应路径中搜索不到相应类),则用其子classloader加载,直到这个类被加载或者抛出相应的异常
这个顺序保证了越重要的类,越先加载;因为一个类只被加载一次(cache),所以如java.lang.System这个类,不能被用户替换(因为是按照bootstrap-->extension-->system的顺序,当要加载java.lang.System类时,其首先从bootstrap的搜索路径中找类)
(3)system/application classloader [系统(应用)类加载器] ,加载来自-classpath或者java.class.path系统属性或者CLASSPATH操作系统属性所指定的JAR类包和类路径。
a.可以通过静态方法ClassLoader.getSystemClassLoader()找到该类加载器。
b.如果没有特别指定,则用户自定义的任何类加载器都将该类加载器作为它的父加载器。可以从源代码看出这一点:
view plaincopy to clipboardprint?
01.protected ClassLoader() {
02. SecurityManager security = System.getSecurityManager();
03. if (security != null) {
04. security.checkCreateClassLoader();
05. }
06. this.parent = getSystemClassLoader();
07. initialized = true;
08. }
protected ClassLoader() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
this.parent = getSystemClassLoader();
initialized = true;
}
classpath路径:
view plaincopy to clipboardprint?
01.class TestSystemClassLoader {
02. public static void main(String[] args) {
03. System.out.println(System.getProperty("java.class.path"));
04. }
05.}
class TestSystemClassLoader {
public static void main(String[] args) {
System.out.println(System.getProperty("java.class.path"));
}
}
结果为:
E:/dev/java/eclipse/TestClassLoader/classes;E:/dev/java/lib/commons-logging-1.1.jar
重要:
classloader加载类用的是全盘负责委托机制。
a.全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入 ;
b.委托机制则是先让parent类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。
二、ClassLoader加载Class的过程
1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
2.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4
3.请求parent classloader载入,如果成功到8,不成功到5
4.请求jvm从bootstrap classloader中载入,如果成功到8
5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7.
6.从文件中载入Class,到8.
7.抛出ClassNotFoundException.
8.返回Class.
源代码如下:
view plaincopy to clipboardprint?
01.ClassLoader类中
02.protected synchronized Class<?> loadClass(String name, boolean resolve)
03. throws ClassNotFoundException
04. {
05. // First, check if the class has already been loaded
06. Class c = findLoadedClass(name);
07. if (c == null) {
08. try {
09. if (parent != null) {
10. c = parent.loadClass(name, false);
11. } else {
12. c = findBootstrapClass0(name);
13. }
14. } catch (ClassNotFoundException e) {
15. // If still not found, then invoke findClass in order
16. // to find the class.
17. c = findClass(name);
18. }
19. }
20. if (resolve) {
21. resolveClass(c);
22. }
23. return c;
24. }
ClassLoader类中
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) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
可以看到当在parent链classloader中和bootstrap classloader中都找不到相应的类时,会调用findClass方法,因此ClassLoader的子类可以重写这个方法,定义自己的找到类的方法
以下是一些类的ClassLoader示例:
view plaincopy to clipboardprint?
01.class TestClassLoader {
02. public static void main(String[] args) {
03. System.out.println(System.class.getClassLoader());
04. System.out.println(javax.swing.JButton.class.getClassLoader());
05. System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
06. System.out.println(org.apache.commons.logging.Log.class.getClassLoader());
07. }
08.}
class TestClassLoader {
public static void main(String[] args) {
System.out.println(System.class.getClassLoader());
System.out.println(javax.swing.JButton.class.getClassLoader());
System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
System.out.println(org.apache.commons.logging.Log.class.getClassLoader());
}
}
输出:
null 其路径在sun.boot.class.path中,由bootstrap classloader加载,所以返回为null(因其不是ClassLoader的子类)
null 其路径在sun.boot.class.path中,由bootstrap classloader加载
sun.misc.Launcher$ExtClassLoader@7259da 路径在java.ext.dirs中,由extension classloader加载
sun.misc.Launcher$AppClassLoader@197d257 由classpath指定,由system classloader加载
查看sun.misc.Launcher的源代码
view plaincopy to clipboardprint?
01.public Launcher() {
02. // Create the extension class loader
03. ClassLoader extcl;
04. try {
05. extcl = ExtClassLoader.getExtClassLoader();
06. } catch (IOException e) {
07. throw new InternalError(
08. "Could not create extension class loader");
09. }
10. // Now create the class loader to use to launch the application
11. try {
12. loader = AppClassLoader.getAppClassLoader(extcl);
13. } catch (IOException e) {
14. throw new InternalError(
15. "Could not create application class loader");
16. }
17. // Also set the context class loader for the primordial thread.
18. Thread.currentThread().setContextClassLoader(loader);
19. // 其他
20.}
public Launcher() {
// Create the extension class loader
ClassLoader extcl;
try {
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
"Could not create extension class loader");
}
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader");
}
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);
// 其他
}
可以看到是由Launcher这个类初始化ExtClassLoader和AppClassLoader类的
ExtClassLoader无parent,而AppClassLoader的parent为 ExtClassLoader
Launcher的getClassLoader()方法
view plaincopy to clipboardprint?
01.public ClassLoader getClassLoader() {
02. return loader;
03. }
04.只返回AppClassLoader
public ClassLoader getClassLoader() {
return loader;
}
只返回AppClassLoader
ExtClassLoader
view plaincopy to clipboardprint?
01.static class ExtClassLoader extends URLClassLoader {
02. private File[] dirs;
03. /**
04. * create an ExtClassLoader. The ExtClassLoader is created
05. * within a context that limits which files it can read
06. */
07. public static ExtClassLoader getExtClassLoader() throws IOException
08. {
09. final File[] dirs = getExtDirs();
10. try {
11. // Prior implementations of this doPrivileged() block supplied
12. // aa synthesized ACC via a call to the private method
13. // ExtClassLoader.getContext().
14. return (ExtClassLoader) AccessController.doPrivileged(
15. new PrivilegedExceptionAction() {
16. public Object run() throws IOException {
17. int len = dirs.length;
18. for (int i = 0; i < len; i++) {
19. MetaIndex.registerDirectory(dirs[i]);
20. }
21. return new ExtClassLoader(dirs);
22. }
23. });
24. } catch (java.security.PrivilegedActionException e) {
25. throw (IOException) e.getException();
26. }
27. }
28.......
29.private static File[] getExtDirs() {
30. String s = System.getProperty("java.ext.dirs");
31. File[] dirs;
32. if (s != null) {
33. StringTokenizer st =
34. new StringTokenizer(s, File.pathSeparator);
35. int count = st.countTokens();
36. dirs = new File[count];
37. for (int i = 0; i < count; i++) {
38. dirs[i] = new File(st.nextToken());
39. }
40. } else {
41. dirs = new File[0];
42. }
43. return dirs;
44. }
static class ExtClassLoader extends URLClassLoader {
private File[] dirs;
/**
* create an ExtClassLoader. The ExtClassLoader is created
* within a context that limits which files it can read
*/
public static ExtClassLoader getExtClassLoader() throws IOException
{
final File[] dirs = getExtDirs();
try {
// Prior implementations of this doPrivileged() block supplied
// aa synthesized ACC via a call to the private method
// ExtClassLoader.getContext().
return (ExtClassLoader) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws IOException {
int len = dirs.length;
for (int i = 0; i < len; i++) {
MetaIndex.registerDirectory(dirs[i]);
}
return new ExtClassLoader(dirs);
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException) e.getException();
}
}
......
private static File[] getExtDirs() {
String s = System.getProperty("java.ext.dirs");
File[] dirs;
if (s != null) {
StringTokenizer st =
new StringTokenizer(s, File.pathSeparator);
int count = st.countTokens();
dirs = new File[count];
for (int i = 0; i < count; i++) {
dirs[i] = new File(st.nextToken());
}
} else {
dirs = new File[0];
}
return dirs;
}
AppClassLoader
view plaincopy to clipboardprint?
01.static class AppClassLoader extends URLClassLoader {
02. public static ClassLoader getAppClassLoader(final ClassLoader extcl)
03. throws IOException
04. {
05. final String s = System.getProperty("java.class.path");
06. final File[] path = (s == null) ? new File[0] : getClassPath(s);
07. // Note: on bugid 4256530
08. // Prior implementations of this doPrivileged() block supplied
09. // a rather restrictive ACC via a call to the private method
10. // AppClassLoader.getContext(). This proved overly restrictive
11. // when loading classes. Specifically it prevent
12. // accessClassInPackage.sun.* grants from being honored.
13. //
14. return (AppClassLoader)
15. AccessController.doPrivileged(new PrivilegedAction() {
16. public Object run() {
17. URL[] urls =
18. (s == null) ? new URL[0] : pathToURLs(path);
19. return new AppClassLoader(urls, extcl);
20. }
21. });
22. }
23.......
static class AppClassLoader extends URLClassLoader {
public static ClassLoader getAppClassLoader(final ClassLoader extcl)
throws IOException
{
final String s = System.getProperty("java.class.path");
final File[] path = (s == null) ? new File[0] : getClassPath(s);
// Note: on bugid 4256530
// Prior implementations of this doPrivileged() block supplied
// a rather restrictive ACC via a call to the private method
// AppClassLoader.getContext(). This proved overly restrictive
// when loading classes. Specifically it prevent
// accessClassInPackage.sun.* grants from being honored.
//
return (AppClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
URL[] urls =
(s == null) ? new URL[0] : pathToURLs(path);
return new AppClassLoader(urls, extcl);
}
});
}
......
Launcher类的getBootstrapClassPath()方法
view plaincopy to clipboardprint?
01.public static URLClassPath getBootstrapClassPath() {
02. String prop = (String)AccessController.doPrivileged(new GetPropertyAction("sun.boot.class.path"));
03. URL[] urls;
04. if (prop != null) {
05. final String path = prop;
06. urls = (URL[])AccessController.doPrivileged(
07. new PrivilegedAction() {
08. public Object run() {
09. File[] classPath = getClassPath(path);
10. int len = classPath.length;
11. Set seenDirs = new HashSet();
12. for (int i = 0; i < len; i++) {
13. File curEntry = classPath[i];
14. // Negative test used to properly handle
15. // nonexistent jars on boot class path
16. if (!curEntry.isDirectory()) {
17. curEntry = curEntry.getParentFile();
18. }
19. if (curEntry != null && seenDirs.add(curEntry)) {
20. MetaIndex.registerDirectory(curEntry);
21. }
22. }
23. return pathToURLs(classPath);
24. }
25. }
26. );
27. } else {
28. urls = new URL[0];
29. }
30. return new URLClassPath(urls, factory);
31. }
public static URLClassPath getBootstrapClassPath() {
String prop = (String)AccessController.doPrivileged(new GetPropertyAction("sun.boot.class.path"));
URL[] urls;
if (prop != null) {
final String path = prop;
urls = (URL[])AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
File[] classPath = getClassPath(path);
int len = classPath.length;
Set seenDirs = new HashSet();
for (int i = 0; i < len; i++) {
File curEntry = classPath[i];
// Negative test used to properly handle
// nonexistent jars on boot class path
if (!curEntry.isDirectory()) {
curEntry = curEntry.getParentFile();
}
if (curEntry != null && seenDirs.add(curEntry)) {
MetaIndex.registerDirectory(curEntry);
}
}
return pathToURLs(classPath);
}
}
);
} else {
urls = new URL[0];
}
return new URLClassPath(urls, factory);
}
从以上代码中可以看到bootstrap classloader使用sun.boot.class.path来加载类,extension classloader使用java.ext.dirs来加载类,而system classloader使用java.class.path来加载类
运行下列程序:
view plaincopy to clipboardprint?
01.class Test1 {
02. public static void main(String[] args) {
03. System.out.println(sun.misc.Launcher.getLauncher().getClass().getClassLoader());
04. }
05.}
class Test1 {
public static void main(String[] args) {
System.out.println(sun.misc.Launcher.getLauncher().getClass().getClassLoader());
}
}
结果为:
null
表明Launcher是由bootstrap classloader来加载的
三、关于Context ClassLoader
在上面Launcher的构造函数中有这么一句: Thread.currentThread().setContextClassLoader(loader); 这句是设置当前线程的classloader,默认是使用的AppClassLoader
这个有什么作用呢?
当线程需要用到某个类,contextClassLoader被请求来载入该类
注意:
(1)Class.forName(String name)载入的是在系统中已经加载入sun.boot.class.path、 java.ext.dirs、 java.class.path路径中的类,而在这几个路径中未加入的类不能载入(报异常)
(2)Class.forName(String name, boolean initialize, ClassLoader loader)可以载入上述三个路径中没有的类,只要指定你的classloader即可
(3)利用ClassLoader可以载入在上述三个路径中没有的类
示例:
view plaincopy to clipboardprint?
01.自定义ClassLoader,从c根目录中读class
02.package Test;
03.public class TestClassLoader extends ClassLoader {
04. protected Map<String, Class> cache = new HashMap<String, Class>();
05.
06. public TestClassLoader() {
07. super();
08. }
09.
10. protected Class<?> findClass(String name) throws ClassNotFoundException {
11. if (cache.get(name) != null) {
12. return cache.get(name);
13. }
14. try {
15. String tname = name.replace('.', '/');
16. File file = new File("c://" + tname + ".class");
17. FileInputStream in = new FileInputStream(file);
18. BufferedInputStream bufIn = new BufferedInputStream(in);
19. ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
20. BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
21. byte[] buffer = new byte[4096];
22. int len = -1;
23. while((len = bufIn.read(buffer)) != -1) {
24. bufOut.write(buffer, 0, len);
25. }
26. bufOut.flush();
27. byteOut.flush();
28. byte[] data = byteOut.toByteArray();
29. Class cls = defineClass(name, data, 0, data.length);
30. cache.put(name, cls);
31. return cls; } catch (IOException e) {
32. e.printStackTrace();
33. }
34. return null;
35. }
36.}
37.class TestLoader {
38. public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
39. ClassLoader cl = Thread.currentThread().getContextClassLoader();
40. System.out.println(Thread.currentThread().toString() + " " + cl.toString());
41. new Thread() {
42. public void run() {
43. ClassLoader cl = Thread.currentThread().getContextClassLoader();
44. System.out.println(Thread.currentThread().toString() + " " + cl.toString());
45.
46. TestClassLoader loader = new TestClassLoader();
47. Thread.currentThread().setContextClassLoader(loader);
48. new Thread() {
49. public void run() {
50. try {
51. ClassLoader cl = Thread.currentThread().getContextClassLoader();
52. System.out.println(Thread.currentThread().toString() + " " + cl.toString());
53. //ClassLoader
54. AbstractTestA test = (AbstractTestA) cl.loadClass("Test.TestAImp1").newInstance();
55. //Class.forName
56. //AbstractTestA test = (AbstractTestA) Class.forName("Test.TestAImp1", true, cl).newInstance(); test.test();
57. } catch (InstantiationException e) {
58. // TODO Auto-generated catch block
59. e.printStackTrace();
60. } catch (IllegalAccessException e) {
61. // TODO Auto-generated catch block
62. e.printStackTrace();
63. } catch (ClassNotFoundException e) {
64. // TODO Auto-generated catch block
65. e.printStackTrace();
66. }
67. }
68. }.start();
69. }
70. }.start();
71. }
72.}
73.//抽象类
74.package Test;
75.public abstract class AbstractTestA {
76. public String a;
77. public void print() {
78. System.out.println("a=" + a);
79. }
80.
81. abstract public void test();
82.}
83.//编译后放入c根目录
84.package Test;
85.public class TestAImp1 extends AbstractTestA {
86. public void test() {
87. System.out.println(Thread.currentThread().toString());
88. System.out.println("Test");
89. }
90.}
自定义ClassLoader,从c根目录中读class
package Test;
public class TestClassLoader extends ClassLoader {
protected Map<String, Class> cache = new HashMap<String, Class>();
public TestClassLoader() {
super();
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (cache.get(name) != null) {
return cache.get(name);
}
try {
String tname = name.replace('.', '/');
File file = new File("c://" + tname + ".class");
FileInputStream in = new FileInputStream(file);
BufferedInputStream bufIn = new BufferedInputStream(in);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
byte[] buffer = new byte[4096];
int len = -1;
while((len = bufIn.read(buffer)) != -1) {
bufOut.write(buffer, 0, len);
}
bufOut.flush();
byteOut.flush();
byte[] data = byteOut.toByteArray();
Class cls = defineClass(name, data, 0, data.length);
cache.put(name, cls);
return cls; } catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
class TestLoader {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
System.out.println(Thread.currentThread().toString() + " " + cl.toString());
new Thread() {
public void run() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
System.out.println(Thread.currentThread().toString() + " " + cl.toString());
TestClassLoader loader = new TestClassLoader();
Thread.currentThread().setContextClassLoader(loader);
new Thread() {
public void run() {
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
System.out.println(Thread.currentThread().toString() + " " + cl.toString());
//ClassLoader
AbstractTestA test = (AbstractTestA) cl.loadClass("Test.TestAImp1").newInstance();
//Class.forName
//AbstractTestA test = (AbstractTestA) Class.forName("Test.TestAImp1", true, cl).newInstance(); test.test();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
}.start();
}
}
//抽象类
package Test;
public abstract class AbstractTestA {
public String a;
public void print() {
System.out.println("a=" + a);
}
abstract public void test();
}
//编译后放入c根目录
package Test;
public class TestAImp1 extends AbstractTestA {
public void test() {
System.out.println(Thread.currentThread().toString());
System.out.println("Test");
}
}
运行结果为:
Thread[main,5,main] sun.misc.Launcher$AppClassLoader@197d257
Thread[Thread-0,5,main] sun.misc.Launcher$AppClassLoader@197d257
Thread[Thread-1,5,main] Test.TestClassLoader@1004901
Thread[Thread-1,5,main]
Test
这也表明了线程间ContextClassLoader的继承性:
(1)main线程默认的 ContextClassLoader为AppClassLoader
(2)新启动线程从原线程处继承 ContextClassLoader
四、关于ClassLoader和Package
其中:String(int offset, int len, char[] arr)为包访问权限
view plaincopy to clipboardprint?
01.package java.lang;
02.public class TestPackage {
03. public static void main(String[] args) {
04. char[] c = "1234567890".toCharArray();
05. String s = new String(0, 10, c);
06. }
07.}
package java.lang;
public class TestPackage {
public static void main(String[] args) {
char[] c = "1234567890".toCharArray();
String s = new String(0, 10, c);
}
}
此代码可以编译通过,但是运行时出现下列错误:
java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
这表明:
Java语言规定,在同一个包中的class,如果没有修饰符,默认为Package权限,包内的class都可以访问。但是这还不够准确。确切的说,只有由同一个ClassLoader装载的class才具有以上的Package权限。比如Bootstrap classloader装载了java.lang.String,AppClassLoader装载了我们自己写的java.lang.TestPackage,它们不能互相访问对方具有Package权限的方法。这样就阻止了恶意代码访问核心类的Package权限方法。
五、关于两个ClassLoader载入同一个类
注意:由两个不同的ClassLoader载入的同一个类,其是不同类型的,因此如果进行赋值会报ClassCastException
示例:
view plaincopy to clipboardprint?
01.package Test;
02.import java.io.*;
03.import java.util.*;
04.public class TestClassLoader extends ClassLoader {
05.
06. protected Map<String, Class> cache = new HashMap<String, Class>();
07.
08. public TestClassLoader() {
09. super();
10. }
11.
12. protected Class<?> findClass(String name) throws ClassNotFoundException {
13. if (cache.get(name) != null) {
14. return cache.get(name);
15. }
16. try {
17. String tname = name.replace('.', '/');
18. File file = new File("c://" + tname + ".class");
19. FileInputStream in = new FileInputStream(file);
20. BufferedInputStream bufIn = new BufferedInputStream(in);
21. ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
22. BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
23. byte[] buffer = new byte[4096];
24. int len = -1;
25. while((len = bufIn.read(buffer)) != -1) {
26. bufOut.write(buffer, 0, len);
27. }
28. bufOut.flush();
29. byteOut.flush();
30. byte[] data = byteOut.toByteArray();
31. Class cls = defineClass(name, data, 0, data.length);
32. cache.put(name, cls);
33. return cls;
34. } catch (IOException e) {
35. e.printStackTrace();
36. }
37. return null;
38. }
39.}
40.class TestLoaderA {
41. public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
42. TestClassLoader loader = new TestClassLoader();
43. System.out.println(TestAImp1.class.getClassLoader());
44. System.out.println(loader.findClass("Test.TestAImp1").getClassLoader());
45. TestAImp1 test = (TestAImp1)loader.findClass("Test.TestAImp1").newInstance();
46. test.test();
47.
48. }
49.}
50.public class TestAImp1 extends AbstractTestA {
51. public void test() {
52. System.out.println(Thread.currentThread().toString());
53. System.out.println("Test");
54. }
55.}
package Test;
import java.io.*;
import java.util.*;
public class TestClassLoader extends ClassLoader {
protected Map<String, Class> cache = new HashMap<String, Class>();
public TestClassLoader() {
super();
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (cache.get(name) != null) {
return cache.get(name);
}
try {
String tname = name.replace('.', '/');
File file = new File("c://" + tname + ".class");
FileInputStream in = new FileInputStream(file);
BufferedInputStream bufIn = new BufferedInputStream(in);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
byte[] buffer = new byte[4096];
int len = -1;
while((len = bufIn.read(buffer)) != -1) {
bufOut.write(buffer, 0, len);
}
bufOut.flush();
byteOut.flush();
byte[] data = byteOut.toByteArray();
Class cls = defineClass(name, data, 0, data.length);
cache.put(name, cls);
return cls;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
class TestLoaderA {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
TestClassLoader loader = new TestClassLoader();
System.out.println(TestAImp1.class.getClassLoader());
System.out.println(loader.findClass("Test.TestAImp1").getClassLoader());
TestAImp1 test = (TestAImp1)loader.findClass("Test.TestAImp1").newInstance();
test.test();
}
}
public class TestAImp1 extends AbstractTestA {
public void test() {
System.out.println(Thread.currentThread().toString());
System.out.println("Test");
}
}
运行以上代码结果:
sun.misc.Launcher$AppClassLoader@197d257
Test.TestClassLoader@1b90b39
Exception in thread "main" java.lang.ClassCastException: Test.TestAImp1
at Test.TestLoaderA.main(TestClassLoader.java:84)
http://blog.csdn.net/lovingprince/archive/2009/06/03/4238695.aspx
http://www.yesky.com/243/1840743.shtml
http://blog.csdn.net/gtuu0123/article/details/4493757
Java为了提供平台无关性,在操作系统之上加入了一层JVM来隔离操作系统特定实现,使所编写的java代码在任何平台都能运行,但是JVM是特定于某一操作系统的
一、当JVM启动时,由三个类加载器对类进行加载:
1.bootstrap classloader
2.extension classloader
3.system classloader
(1)bootstrap classloader[ 引导类加载器] 是由JVM实现的,不是java.lang.ClassLoader的子类 ,它负责加载Java的核心类,其加载的类由 sun.boot.class.path指定,或者在 执行java命令时使用-Xbootclasspath选项或使用-D选项指定sun.boot.class.path系统属性值
说明:
-Dproperty_name=property_value 指定属性的值;
-Xbootclasspath 改变虚拟机装载缺省系统运行包rt.jar,而从-Xbootclasspath中设定的搜索路径中装载系统运行类
输出加载的核心类库:
view plaincopy to clipboardprint?
01.public class TestBootstrapClassLoader {
02. public static void main(String[] args) {
03. URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
04. for (int i = 0; i < urls.length; i++) {
05. System.out.println(urls[i].toExternalForm());
06. }
07. }
08.}
public class TestBootstrapClassLoader {
public static void main(String[] args) {
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
}
}
输出结果:
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/rt.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/i18n.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/sunrsasign.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/jsse.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/jce.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/lib/charsets.jar
file:/E:/MyEclipse%205.1.1%20GA/jre/classes
(2) extension classloader[扩展类加载器] ,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。这为引入除Java核心类以外的新功能提供了一个标准机制。在这个实例上调用方法getParent()总是返回空值null,因为引导加载器bootstrap classloader不是一个真正的ClassLoader实例。
view plaincopy to clipboardprint?
01.class TestExtensionClassLoader {
02. public static void main(String[] args) {
03. System.out.println(System.getProperty("java.ext.dirs"));
04. ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
05. System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
06. }
07.}
class TestExtensionClassLoader {
public static void main(String[] args) {
System.out.println(System.getProperty("java.ext.dirs"));
ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
}
}
输出结果:
E:/MyEclipse 5.1.1 GA/jre/lib/ext
the parent of extension classloader : null
以上这段代码也表明了下列父子关系或加载顺序:
bootstrap classloader(因其不是ClassLoader的子类,null)-->extension classloader-->system classloader
这也表明了jvm在加载类的顺序,当加载一个类时(假设其未加载),先找到最顶层的classloader,如果其可以加载这个类(或者已经加载了这个类),则返回这个类;如果其不能加载类(换个说法:在相应路径中搜索不到相应类),则用其子classloader加载,直到这个类被加载或者抛出相应的异常
这个顺序保证了越重要的类,越先加载;因为一个类只被加载一次(cache),所以如java.lang.System这个类,不能被用户替换(因为是按照bootstrap-->extension-->system的顺序,当要加载java.lang.System类时,其首先从bootstrap的搜索路径中找类)
(3)system/application classloader [系统(应用)类加载器] ,加载来自-classpath或者java.class.path系统属性或者CLASSPATH操作系统属性所指定的JAR类包和类路径。
a.可以通过静态方法ClassLoader.getSystemClassLoader()找到该类加载器。
b.如果没有特别指定,则用户自定义的任何类加载器都将该类加载器作为它的父加载器。可以从源代码看出这一点:
view plaincopy to clipboardprint?
01.protected ClassLoader() {
02. SecurityManager security = System.getSecurityManager();
03. if (security != null) {
04. security.checkCreateClassLoader();
05. }
06. this.parent = getSystemClassLoader();
07. initialized = true;
08. }
protected ClassLoader() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
this.parent = getSystemClassLoader();
initialized = true;
}
classpath路径:
view plaincopy to clipboardprint?
01.class TestSystemClassLoader {
02. public static void main(String[] args) {
03. System.out.println(System.getProperty("java.class.path"));
04. }
05.}
class TestSystemClassLoader {
public static void main(String[] args) {
System.out.println(System.getProperty("java.class.path"));
}
}
结果为:
E:/dev/java/eclipse/TestClassLoader/classes;E:/dev/java/lib/commons-logging-1.1.jar
重要:
classloader加载类用的是全盘负责委托机制。
a.全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入 ;
b.委托机制则是先让parent类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。
二、ClassLoader加载Class的过程
1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
2.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4
3.请求parent classloader载入,如果成功到8,不成功到5
4.请求jvm从bootstrap classloader中载入,如果成功到8
5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7.
6.从文件中载入Class,到8.
7.抛出ClassNotFoundException.
8.返回Class.
源代码如下:
view plaincopy to clipboardprint?
01.ClassLoader类中
02.protected synchronized Class<?> loadClass(String name, boolean resolve)
03. throws ClassNotFoundException
04. {
05. // First, check if the class has already been loaded
06. Class c = findLoadedClass(name);
07. if (c == null) {
08. try {
09. if (parent != null) {
10. c = parent.loadClass(name, false);
11. } else {
12. c = findBootstrapClass0(name);
13. }
14. } catch (ClassNotFoundException e) {
15. // If still not found, then invoke findClass in order
16. // to find the class.
17. c = findClass(name);
18. }
19. }
20. if (resolve) {
21. resolveClass(c);
22. }
23. return c;
24. }
ClassLoader类中
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) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
可以看到当在parent链classloader中和bootstrap classloader中都找不到相应的类时,会调用findClass方法,因此ClassLoader的子类可以重写这个方法,定义自己的找到类的方法
以下是一些类的ClassLoader示例:
view plaincopy to clipboardprint?
01.class TestClassLoader {
02. public static void main(String[] args) {
03. System.out.println(System.class.getClassLoader());
04. System.out.println(javax.swing.JButton.class.getClassLoader());
05. System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
06. System.out.println(org.apache.commons.logging.Log.class.getClassLoader());
07. }
08.}
class TestClassLoader {
public static void main(String[] args) {
System.out.println(System.class.getClassLoader());
System.out.println(javax.swing.JButton.class.getClassLoader());
System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
System.out.println(org.apache.commons.logging.Log.class.getClassLoader());
}
}
输出:
null 其路径在sun.boot.class.path中,由bootstrap classloader加载,所以返回为null(因其不是ClassLoader的子类)
null 其路径在sun.boot.class.path中,由bootstrap classloader加载
sun.misc.Launcher$ExtClassLoader@7259da 路径在java.ext.dirs中,由extension classloader加载
sun.misc.Launcher$AppClassLoader@197d257 由classpath指定,由system classloader加载
查看sun.misc.Launcher的源代码
view plaincopy to clipboardprint?
01.public Launcher() {
02. // Create the extension class loader
03. ClassLoader extcl;
04. try {
05. extcl = ExtClassLoader.getExtClassLoader();
06. } catch (IOException e) {
07. throw new InternalError(
08. "Could not create extension class loader");
09. }
10. // Now create the class loader to use to launch the application
11. try {
12. loader = AppClassLoader.getAppClassLoader(extcl);
13. } catch (IOException e) {
14. throw new InternalError(
15. "Could not create application class loader");
16. }
17. // Also set the context class loader for the primordial thread.
18. Thread.currentThread().setContextClassLoader(loader);
19. // 其他
20.}
public Launcher() {
// Create the extension class loader
ClassLoader extcl;
try {
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
"Could not create extension class loader");
}
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader");
}
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);
// 其他
}
可以看到是由Launcher这个类初始化ExtClassLoader和AppClassLoader类的
ExtClassLoader无parent,而AppClassLoader的parent为 ExtClassLoader
Launcher的getClassLoader()方法
view plaincopy to clipboardprint?
01.public ClassLoader getClassLoader() {
02. return loader;
03. }
04.只返回AppClassLoader
public ClassLoader getClassLoader() {
return loader;
}
只返回AppClassLoader
ExtClassLoader
view plaincopy to clipboardprint?
01.static class ExtClassLoader extends URLClassLoader {
02. private File[] dirs;
03. /**
04. * create an ExtClassLoader. The ExtClassLoader is created
05. * within a context that limits which files it can read
06. */
07. public static ExtClassLoader getExtClassLoader() throws IOException
08. {
09. final File[] dirs = getExtDirs();
10. try {
11. // Prior implementations of this doPrivileged() block supplied
12. // aa synthesized ACC via a call to the private method
13. // ExtClassLoader.getContext().
14. return (ExtClassLoader) AccessController.doPrivileged(
15. new PrivilegedExceptionAction() {
16. public Object run() throws IOException {
17. int len = dirs.length;
18. for (int i = 0; i < len; i++) {
19. MetaIndex.registerDirectory(dirs[i]);
20. }
21. return new ExtClassLoader(dirs);
22. }
23. });
24. } catch (java.security.PrivilegedActionException e) {
25. throw (IOException) e.getException();
26. }
27. }
28.......
29.private static File[] getExtDirs() {
30. String s = System.getProperty("java.ext.dirs");
31. File[] dirs;
32. if (s != null) {
33. StringTokenizer st =
34. new StringTokenizer(s, File.pathSeparator);
35. int count = st.countTokens();
36. dirs = new File[count];
37. for (int i = 0; i < count; i++) {
38. dirs[i] = new File(st.nextToken());
39. }
40. } else {
41. dirs = new File[0];
42. }
43. return dirs;
44. }
static class ExtClassLoader extends URLClassLoader {
private File[] dirs;
/**
* create an ExtClassLoader. The ExtClassLoader is created
* within a context that limits which files it can read
*/
public static ExtClassLoader getExtClassLoader() throws IOException
{
final File[] dirs = getExtDirs();
try {
// Prior implementations of this doPrivileged() block supplied
// aa synthesized ACC via a call to the private method
// ExtClassLoader.getContext().
return (ExtClassLoader) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws IOException {
int len = dirs.length;
for (int i = 0; i < len; i++) {
MetaIndex.registerDirectory(dirs[i]);
}
return new ExtClassLoader(dirs);
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException) e.getException();
}
}
......
private static File[] getExtDirs() {
String s = System.getProperty("java.ext.dirs");
File[] dirs;
if (s != null) {
StringTokenizer st =
new StringTokenizer(s, File.pathSeparator);
int count = st.countTokens();
dirs = new File[count];
for (int i = 0; i < count; i++) {
dirs[i] = new File(st.nextToken());
}
} else {
dirs = new File[0];
}
return dirs;
}
AppClassLoader
view plaincopy to clipboardprint?
01.static class AppClassLoader extends URLClassLoader {
02. public static ClassLoader getAppClassLoader(final ClassLoader extcl)
03. throws IOException
04. {
05. final String s = System.getProperty("java.class.path");
06. final File[] path = (s == null) ? new File[0] : getClassPath(s);
07. // Note: on bugid 4256530
08. // Prior implementations of this doPrivileged() block supplied
09. // a rather restrictive ACC via a call to the private method
10. // AppClassLoader.getContext(). This proved overly restrictive
11. // when loading classes. Specifically it prevent
12. // accessClassInPackage.sun.* grants from being honored.
13. //
14. return (AppClassLoader)
15. AccessController.doPrivileged(new PrivilegedAction() {
16. public Object run() {
17. URL[] urls =
18. (s == null) ? new URL[0] : pathToURLs(path);
19. return new AppClassLoader(urls, extcl);
20. }
21. });
22. }
23.......
static class AppClassLoader extends URLClassLoader {
public static ClassLoader getAppClassLoader(final ClassLoader extcl)
throws IOException
{
final String s = System.getProperty("java.class.path");
final File[] path = (s == null) ? new File[0] : getClassPath(s);
// Note: on bugid 4256530
// Prior implementations of this doPrivileged() block supplied
// a rather restrictive ACC via a call to the private method
// AppClassLoader.getContext(). This proved overly restrictive
// when loading classes. Specifically it prevent
// accessClassInPackage.sun.* grants from being honored.
//
return (AppClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
URL[] urls =
(s == null) ? new URL[0] : pathToURLs(path);
return new AppClassLoader(urls, extcl);
}
});
}
......
Launcher类的getBootstrapClassPath()方法
view plaincopy to clipboardprint?
01.public static URLClassPath getBootstrapClassPath() {
02. String prop = (String)AccessController.doPrivileged(new GetPropertyAction("sun.boot.class.path"));
03. URL[] urls;
04. if (prop != null) {
05. final String path = prop;
06. urls = (URL[])AccessController.doPrivileged(
07. new PrivilegedAction() {
08. public Object run() {
09. File[] classPath = getClassPath(path);
10. int len = classPath.length;
11. Set seenDirs = new HashSet();
12. for (int i = 0; i < len; i++) {
13. File curEntry = classPath[i];
14. // Negative test used to properly handle
15. // nonexistent jars on boot class path
16. if (!curEntry.isDirectory()) {
17. curEntry = curEntry.getParentFile();
18. }
19. if (curEntry != null && seenDirs.add(curEntry)) {
20. MetaIndex.registerDirectory(curEntry);
21. }
22. }
23. return pathToURLs(classPath);
24. }
25. }
26. );
27. } else {
28. urls = new URL[0];
29. }
30. return new URLClassPath(urls, factory);
31. }
public static URLClassPath getBootstrapClassPath() {
String prop = (String)AccessController.doPrivileged(new GetPropertyAction("sun.boot.class.path"));
URL[] urls;
if (prop != null) {
final String path = prop;
urls = (URL[])AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
File[] classPath = getClassPath(path);
int len = classPath.length;
Set seenDirs = new HashSet();
for (int i = 0; i < len; i++) {
File curEntry = classPath[i];
// Negative test used to properly handle
// nonexistent jars on boot class path
if (!curEntry.isDirectory()) {
curEntry = curEntry.getParentFile();
}
if (curEntry != null && seenDirs.add(curEntry)) {
MetaIndex.registerDirectory(curEntry);
}
}
return pathToURLs(classPath);
}
}
);
} else {
urls = new URL[0];
}
return new URLClassPath(urls, factory);
}
从以上代码中可以看到bootstrap classloader使用sun.boot.class.path来加载类,extension classloader使用java.ext.dirs来加载类,而system classloader使用java.class.path来加载类
运行下列程序:
view plaincopy to clipboardprint?
01.class Test1 {
02. public static void main(String[] args) {
03. System.out.println(sun.misc.Launcher.getLauncher().getClass().getClassLoader());
04. }
05.}
class Test1 {
public static void main(String[] args) {
System.out.println(sun.misc.Launcher.getLauncher().getClass().getClassLoader());
}
}
结果为:
null
表明Launcher是由bootstrap classloader来加载的
三、关于Context ClassLoader
在上面Launcher的构造函数中有这么一句: Thread.currentThread().setContextClassLoader(loader); 这句是设置当前线程的classloader,默认是使用的AppClassLoader
这个有什么作用呢?
当线程需要用到某个类,contextClassLoader被请求来载入该类
注意:
(1)Class.forName(String name)载入的是在系统中已经加载入sun.boot.class.path、 java.ext.dirs、 java.class.path路径中的类,而在这几个路径中未加入的类不能载入(报异常)
(2)Class.forName(String name, boolean initialize, ClassLoader loader)可以载入上述三个路径中没有的类,只要指定你的classloader即可
(3)利用ClassLoader可以载入在上述三个路径中没有的类
示例:
view plaincopy to clipboardprint?
01.自定义ClassLoader,从c根目录中读class
02.package Test;
03.public class TestClassLoader extends ClassLoader {
04. protected Map<String, Class> cache = new HashMap<String, Class>();
05.
06. public TestClassLoader() {
07. super();
08. }
09.
10. protected Class<?> findClass(String name) throws ClassNotFoundException {
11. if (cache.get(name) != null) {
12. return cache.get(name);
13. }
14. try {
15. String tname = name.replace('.', '/');
16. File file = new File("c://" + tname + ".class");
17. FileInputStream in = new FileInputStream(file);
18. BufferedInputStream bufIn = new BufferedInputStream(in);
19. ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
20. BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
21. byte[] buffer = new byte[4096];
22. int len = -1;
23. while((len = bufIn.read(buffer)) != -1) {
24. bufOut.write(buffer, 0, len);
25. }
26. bufOut.flush();
27. byteOut.flush();
28. byte[] data = byteOut.toByteArray();
29. Class cls = defineClass(name, data, 0, data.length);
30. cache.put(name, cls);
31. return cls; } catch (IOException e) {
32. e.printStackTrace();
33. }
34. return null;
35. }
36.}
37.class TestLoader {
38. public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
39. ClassLoader cl = Thread.currentThread().getContextClassLoader();
40. System.out.println(Thread.currentThread().toString() + " " + cl.toString());
41. new Thread() {
42. public void run() {
43. ClassLoader cl = Thread.currentThread().getContextClassLoader();
44. System.out.println(Thread.currentThread().toString() + " " + cl.toString());
45.
46. TestClassLoader loader = new TestClassLoader();
47. Thread.currentThread().setContextClassLoader(loader);
48. new Thread() {
49. public void run() {
50. try {
51. ClassLoader cl = Thread.currentThread().getContextClassLoader();
52. System.out.println(Thread.currentThread().toString() + " " + cl.toString());
53. //ClassLoader
54. AbstractTestA test = (AbstractTestA) cl.loadClass("Test.TestAImp1").newInstance();
55. //Class.forName
56. //AbstractTestA test = (AbstractTestA) Class.forName("Test.TestAImp1", true, cl).newInstance(); test.test();
57. } catch (InstantiationException e) {
58. // TODO Auto-generated catch block
59. e.printStackTrace();
60. } catch (IllegalAccessException e) {
61. // TODO Auto-generated catch block
62. e.printStackTrace();
63. } catch (ClassNotFoundException e) {
64. // TODO Auto-generated catch block
65. e.printStackTrace();
66. }
67. }
68. }.start();
69. }
70. }.start();
71. }
72.}
73.//抽象类
74.package Test;
75.public abstract class AbstractTestA {
76. public String a;
77. public void print() {
78. System.out.println("a=" + a);
79. }
80.
81. abstract public void test();
82.}
83.//编译后放入c根目录
84.package Test;
85.public class TestAImp1 extends AbstractTestA {
86. public void test() {
87. System.out.println(Thread.currentThread().toString());
88. System.out.println("Test");
89. }
90.}
自定义ClassLoader,从c根目录中读class
package Test;
public class TestClassLoader extends ClassLoader {
protected Map<String, Class> cache = new HashMap<String, Class>();
public TestClassLoader() {
super();
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (cache.get(name) != null) {
return cache.get(name);
}
try {
String tname = name.replace('.', '/');
File file = new File("c://" + tname + ".class");
FileInputStream in = new FileInputStream(file);
BufferedInputStream bufIn = new BufferedInputStream(in);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
byte[] buffer = new byte[4096];
int len = -1;
while((len = bufIn.read(buffer)) != -1) {
bufOut.write(buffer, 0, len);
}
bufOut.flush();
byteOut.flush();
byte[] data = byteOut.toByteArray();
Class cls = defineClass(name, data, 0, data.length);
cache.put(name, cls);
return cls; } catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
class TestLoader {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
System.out.println(Thread.currentThread().toString() + " " + cl.toString());
new Thread() {
public void run() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
System.out.println(Thread.currentThread().toString() + " " + cl.toString());
TestClassLoader loader = new TestClassLoader();
Thread.currentThread().setContextClassLoader(loader);
new Thread() {
public void run() {
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
System.out.println(Thread.currentThread().toString() + " " + cl.toString());
//ClassLoader
AbstractTestA test = (AbstractTestA) cl.loadClass("Test.TestAImp1").newInstance();
//Class.forName
//AbstractTestA test = (AbstractTestA) Class.forName("Test.TestAImp1", true, cl).newInstance(); test.test();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
}.start();
}
}
//抽象类
package Test;
public abstract class AbstractTestA {
public String a;
public void print() {
System.out.println("a=" + a);
}
abstract public void test();
}
//编译后放入c根目录
package Test;
public class TestAImp1 extends AbstractTestA {
public void test() {
System.out.println(Thread.currentThread().toString());
System.out.println("Test");
}
}
运行结果为:
Thread[main,5,main] sun.misc.Launcher$AppClassLoader@197d257
Thread[Thread-0,5,main] sun.misc.Launcher$AppClassLoader@197d257
Thread[Thread-1,5,main] Test.TestClassLoader@1004901
Thread[Thread-1,5,main]
Test
这也表明了线程间ContextClassLoader的继承性:
(1)main线程默认的 ContextClassLoader为AppClassLoader
(2)新启动线程从原线程处继承 ContextClassLoader
四、关于ClassLoader和Package
其中:String(int offset, int len, char[] arr)为包访问权限
view plaincopy to clipboardprint?
01.package java.lang;
02.public class TestPackage {
03. public static void main(String[] args) {
04. char[] c = "1234567890".toCharArray();
05. String s = new String(0, 10, c);
06. }
07.}
package java.lang;
public class TestPackage {
public static void main(String[] args) {
char[] c = "1234567890".toCharArray();
String s = new String(0, 10, c);
}
}
此代码可以编译通过,但是运行时出现下列错误:
java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
这表明:
Java语言规定,在同一个包中的class,如果没有修饰符,默认为Package权限,包内的class都可以访问。但是这还不够准确。确切的说,只有由同一个ClassLoader装载的class才具有以上的Package权限。比如Bootstrap classloader装载了java.lang.String,AppClassLoader装载了我们自己写的java.lang.TestPackage,它们不能互相访问对方具有Package权限的方法。这样就阻止了恶意代码访问核心类的Package权限方法。
五、关于两个ClassLoader载入同一个类
注意:由两个不同的ClassLoader载入的同一个类,其是不同类型的,因此如果进行赋值会报ClassCastException
示例:
view plaincopy to clipboardprint?
01.package Test;
02.import java.io.*;
03.import java.util.*;
04.public class TestClassLoader extends ClassLoader {
05.
06. protected Map<String, Class> cache = new HashMap<String, Class>();
07.
08. public TestClassLoader() {
09. super();
10. }
11.
12. protected Class<?> findClass(String name) throws ClassNotFoundException {
13. if (cache.get(name) != null) {
14. return cache.get(name);
15. }
16. try {
17. String tname = name.replace('.', '/');
18. File file = new File("c://" + tname + ".class");
19. FileInputStream in = new FileInputStream(file);
20. BufferedInputStream bufIn = new BufferedInputStream(in);
21. ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
22. BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
23. byte[] buffer = new byte[4096];
24. int len = -1;
25. while((len = bufIn.read(buffer)) != -1) {
26. bufOut.write(buffer, 0, len);
27. }
28. bufOut.flush();
29. byteOut.flush();
30. byte[] data = byteOut.toByteArray();
31. Class cls = defineClass(name, data, 0, data.length);
32. cache.put(name, cls);
33. return cls;
34. } catch (IOException e) {
35. e.printStackTrace();
36. }
37. return null;
38. }
39.}
40.class TestLoaderA {
41. public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
42. TestClassLoader loader = new TestClassLoader();
43. System.out.println(TestAImp1.class.getClassLoader());
44. System.out.println(loader.findClass("Test.TestAImp1").getClassLoader());
45. TestAImp1 test = (TestAImp1)loader.findClass("Test.TestAImp1").newInstance();
46. test.test();
47.
48. }
49.}
50.public class TestAImp1 extends AbstractTestA {
51. public void test() {
52. System.out.println(Thread.currentThread().toString());
53. System.out.println("Test");
54. }
55.}
package Test;
import java.io.*;
import java.util.*;
public class TestClassLoader extends ClassLoader {
protected Map<String, Class> cache = new HashMap<String, Class>();
public TestClassLoader() {
super();
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (cache.get(name) != null) {
return cache.get(name);
}
try {
String tname = name.replace('.', '/');
File file = new File("c://" + tname + ".class");
FileInputStream in = new FileInputStream(file);
BufferedInputStream bufIn = new BufferedInputStream(in);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(byteOut);
byte[] buffer = new byte[4096];
int len = -1;
while((len = bufIn.read(buffer)) != -1) {
bufOut.write(buffer, 0, len);
}
bufOut.flush();
byteOut.flush();
byte[] data = byteOut.toByteArray();
Class cls = defineClass(name, data, 0, data.length);
cache.put(name, cls);
return cls;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
class TestLoaderA {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
TestClassLoader loader = new TestClassLoader();
System.out.println(TestAImp1.class.getClassLoader());
System.out.println(loader.findClass("Test.TestAImp1").getClassLoader());
TestAImp1 test = (TestAImp1)loader.findClass("Test.TestAImp1").newInstance();
test.test();
}
}
public class TestAImp1 extends AbstractTestA {
public void test() {
System.out.println(Thread.currentThread().toString());
System.out.println("Test");
}
}
运行以上代码结果:
sun.misc.Launcher$AppClassLoader@197d257
Test.TestClassLoader@1b90b39
Exception in thread "main" java.lang.ClassCastException: Test.TestAImp1
at Test.TestLoaderA.main(TestClassLoader.java:84)
相关推荐
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。...通过研究"InternalsOfClassloadingSrc"这样的项目,我们可以更深入地学习和实践ClassLoader的定制。
总的来说,"classloader-playground"是一个实践和研究Java类加载机制的实用工具。通过这个项目,开发者不仅可以深入了解Java虚拟机的工作原理,还能掌握如何定制类加载器以满足特定场景的需求,提升系统的灵活性和可...
【ClassLoader 深入解析】 在Java编程语言中,ClassLoader是一个至关重要的组件,它负责加载类文件到Java虚拟机(JVM)中,使得程序能够运行。...对于Java开发者来说,深入研究ClassLoader是提升技能的重要一环。
### 深入研究Java类加载机制 #### 一、Java类加载机制概述 Java类加载机制是Java程序运行的第一步,它对于理解Java虚拟机(JVM)的行为至关重要。类加载过程涉及到类的加载、链接(验证、准备、解析)、初始化等...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中,使得...通过深入研究"ClassLoader小例子",你可以更好地理解Java的类加载机制,并为自己的项目开发带来更多的灵活性。
通过研究`ClassLoader`源码,我们可以更深入地理解Java的运行机制,这对于解决一些高级问题,如类冲突、模块化开发等具有重要价值。同时,自定义`ClassLoader`也是Java企业级应用、服务器插件框架以及动态部署场景中...
1. 源码分析:研究ClassLoader的源码,了解其内部实现,特别是加载类的逻辑。 2. 类加载顺序:观察不同类加载器加载类的顺序,验证双亲委派模型。 3. 动态加载:创建自己的类加载器,尝试动态加载新的类,实现代码的...
本文旨在深入剖析Tomcat中特有的类加载器(ClassLoader)体系结构,帮助读者理解Tomcat如何管理和加载不同类型的类库。 #### 二、Tomcat的ClassLoader体系结构 Tomcat采用了独特的类加载机制来处理不同的类库加载...
总的来说,深入研究Tomcat 5.0.18的ClassLoader源码,不仅可以提升我们的技术水平,还能让我们更好地应对Java Web开发中的挑战。对于那些想要深入理解Java类加载机制和Tomcat内部工作的开发者,这是一个不可多得的...
在Java编程语言中,`ClassLoader`是一个至关重要的组件,它负责加载类到...通过研究"**classloader-study.zip**"的内容,你将有机会提升对Java动态加载和卸载类的理解,这对于开发更高级的Java应用程序和框架至关重要。
在Java开发过程中,为了提高开发效率和调试便捷性,我们经常需要实现类的热替换...这个压缩包中的源码可能就是展示如何实现这个功能的一个实例,你可以仔细研究这些代码,加深对Java类加载机制和热替换技术的理解。
《深入解析java.lang》 Java语言的核心库之一就是`java.lang`包,它包含了Java程序设计中最基础的类和接口,...通过深入研究`java.lang`,我们可以更好地理解Java的内在机制,并能更熟练地运用这些工具来解决问题。
在深入理解Java虚拟机的过程中,我们需要掌握以下几个关键知识点: 1. **字节码**:Java源代码编译后生成的中间表示,以`.class`文件形式存在,由JVM负责解释执行。 2. **类加载器**:负责加载类到JVM内存中,包括...
在理解了类加载器的工作原理后,我们可以通过标签"源码"来深入研究其实现细节。分析源码可以帮助我们更好地理解类加载器如何查找、加载和解析类。同时,"工具"标签可能暗示这个例子中还包含了一些辅助工具或技巧,...
通过深入研究JVM,开发者可以优化代码性能,解决内存泄漏、性能瓶颈等问题,提高软件的稳定性和效率。 书中详细讲解了JVM的生命周期管理,包括类加载机制,即如何从磁盘加载类到内存,以及类的加载、连接、初始化等...
在深入研究Java RT.jar源代码时,我们可以对Java的底层实现有更深入的理解,从而提升编程技能和解决问题的能力。 1. **基础类和接口**:Java RT包中包含了许多基础类,如`Object`、`String`、`Integer`、`...
《Tomcat类加载机制——ClassLoader详解》 在Java Web开发中,Tomcat作为最常用的Servlet容器,其类加载机制对于...通过阅读和研究Tomcat源码,我们可以更深入地了解这一机制,从而更好地驾驭这个强大的Web服务器。