java ClassLoader机制和如何加载外部class文件(含代码)

Java类的生命周期

 生命周期有:加载(Loading)--》验证(Verification)--》准备(Preparation)---》解析(Resolution)--》初始化(Initiation)---》使用(Using)----》卸载(Unloading)。 其中标黄的验证---》准备---》解析被称为连接(Linking)。

就代码执行而言:

1.连接阶段:不执行程序员代码

2.加载阶段:可以重写ClassLoader来执行我们的代码

3.连接后阶段:执行该类的代码

ClassLoader:

ClassLoader是为了将class文件的byte数组,主要的方法是findClass用于查找类。

Java7有个迅速将File编程byte[]的方法:

		byte[] cLassBytes = null;
		Path path;
		try {
			path = Paths.get(new URI("file:///D:/MyScript/TestClassLoader.class"));
			cLassBytes = Files.readAllBytes(path);

每个ClassLoader对象都有一个ClassLoader类型的字段,暂且成为parent。当调用本类的loadClass方法加载类时,会先调用parent的ClassLoader,如果他没找到,才会调用本类的findClass方法去查找类。(这样,应用的Launcher$AppClassLoader也可以通过BootStrapClassLoader来调用String类了)。

查找类的顺序,与对应的ClassLoader

系统查找类的顺序是:

1).Bootstrap classes: the runtime classes in rt.jar, internationalization classes in i18n.jar, and others.

2).Installed extensions: classes in JAR files in the lib/ext directory of the JRE, and in the system-wide, platform-specific extension directory (such as /usr/jdk/packages/lib/ext on the Solaris™ Operating System, but note that use of this directory applies only to Java™ 6 and later).

3).The class path: classes, including classes in JAR files, on paths specified by the system property java.class.path. If a JAR file on the class path has a manifest with the Class-Path attribute, JAR files specified by the Class-Path attribute will be searched also. By default, thejava.class.path property's value is ., the current directory. You can change the value by using the -classpath or -cp command-line options, or setting the CLASSPATH environment variable. The command-line options override the setting of the CLASSPATH environment variable.

中文就是:

1)rt.jar等(这个jar是什么呢?你用java -verbose 类名 运行下就看到了:Loaded java.io.File from C:\Program Files\Java\jre1.8.0_31\lib\rt.jar,也就是经常调用的String、Long等类,属于SDK中的)(用BootStrapClassLoader加载)

2) SDK中的拓展类,包名为javax的(java和javax都是Java的API(Application Programming Interface)包,java是核心包,javax的x是extension的意思);

(用Launcher$ExtClassLoader加载)

3) 系统环境变量CLASSPATH的路径,当前目录(或者用命令行带 -classpath重新)

(用Launcher$AppClassLoader加载)

可是我的类文件在D:\MyScript\TestClassLoader.class不在上述三种。

2:解决方案

1.场景:我想加载一个d盘上的类,路径是:D:\MyScript\TestClassLoader.class,其不在上述三种情况。

通过重写一个ClassLoader进行加载,不过有现成的URLClassLoader我们就不要重造轮子了。

自定义ClassLoader代码

public class MyClassLoader extends ClassLoader{
	
	@Override
	protected Class findClass(String className)
			throws ClassNotFoundException {
		byte[] cLassBytes = null;
		//Java 7有下列API
		Path path;
		try {
			path = Paths.get(new URI("file:///D:/MyScript/TestClassLoader.class"));
			cLassBytes = Files.readAllBytes(path);
		} catch (IOException | URISyntaxException e) {
			e.printStackTrace();
		}
		Class cLass = defineClass(cLassBytes, 0, cLassBytes.length);
		return cLass;
	}
}

使用的时候:
			Class.forName("TestClassLoader", true, new MyClassLoader());

用URLClassLoader来简化
		  ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

		    // This URL for a directory will be searched *recursively*
		    URL classes;
			try {
				classes = new URL( "file:///D:/MyScript/" );

		    ClassLoader custom = 
		        new URLClassLoader( new URL[] { classes }, systemClassLoader );

		    // this class should be loaded from your directory
		    Class< ? > clazz = custom.loadClass( "TestClassLoader" ); 

		    Method[] methods = clazz.getDeclaredMethods();
		    for (Method method : methods) {
				System.out.println(method.getName());
			}
URLClassLoader用的URL只能接受目录和jar包:

结尾: /代表该目录下的来; 非/而是文件则默认为jar包。

贴一个jar包的代码:

public URL findResource(String name) {
try {
File file = new File(jarFile);
String url = file.toURL().toString();
return new URL("jar:"+url+"!/"+name);
} catch (Exception e) {
return null;
}

}	

另外我用反射来验证类是否加载成功了,clazz.newInstance()也可以生成相关代码。

你可能感兴趣的:(java)