1.类加载器的最终功能是将java字节码转换成JVM中的Class对象。
实例代码:
class FileSystemClassloader extends ClassLoader {
private String directory;
public FileSystemClassloader(String directory) {
this.directory = directory;
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
byte[] clsBytes = getClassBytes(name);
if(clsBytes == null)
throw new ClassNotFoundException();
return defineClass(name, clsBytes, 0, clsBytes.length);
}
private byte[] getClassBytes(String name) {
String location = getClassLoc(name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream fis = null;
try {
fis = new FileInputStream(location);
byte[] buffer = new byte[4096];
int readLen = 0;
while ((readLen = fis.read(buffer)) != -1) {
baos.write(buffer, 0, readLen);
}
baos.flush();
return baos.toByteArray();
} catch(IOException e) {
e.printStackTrace();
} finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
private String getClassLoc(String name) {
return this.directory + File.separatorChar + name.replace('.', File.separatorChar) + ".class";
}
}
//引导类加载器加载路径
System.out.println("sun.boot.class.path:" + System.getProperty("sun.boot.class.path"));
//扩展类加载器加载路径
System.out.println("java.ext.dirs:" + System.getProperty("java.ext.dirs"));
//系统类加载器加载路径
System.out.println("java.class.path:" +System.getProperty("java.class.path"));
2.Java虚拟机中是根据类加载器+类名来区分对象的,所以不同类加载器加载的同一段字节码是两个不同对象,可通过以下代码测试
String className = "com.meteor.classloader.example.Sample";
Class<?> cls1 = fscl1.loadClass(className);
Class<?> cls2 = fscl2.loadClass(className);
System.out.println("cls1 == cls2?" + (cls1 == cls2));
这段代码测试中如果一直打印true,请用上面代码输出加载类的路径,检查类是被哪个加载器加载的。测试过程如用eclipse等工具,还有路径问题,导致类一直由AppClassLoader加载。
3.线程上下文类加载器
上下文类加载器解决了加载SPI(Service Provider Interface)实现类的方式,父子委托的加载模式并不总适用于Java应用。Java提供了很多SPI接口,如JDBC,JNDI等,这些接口的定义由引导类加载器加载,而实现一般由系统类加载器加载,最终导致类型转换的问题。对于SPI的加载问题,解决办法就是让核心JNDI类使用线程上下文类加载器加载(此处未验证,未看到源代码),打通类加载器的层次结构。
4.Web容器与类加载器
Web容器一般有自己的加载方式,请参见Tomcat的ClassLoader的实现。
Tomcat中的WebappClassLoader实现了ClassLoader的loadClass方法,一般自定义Class,建议实现ClassLoader的findClass方法(仅限于一般小的改动,Tomcat的实现比较复杂,对Class的加载有自己的方式)
5.OSGI与类加载器
学习中。