Java Class Loader Code Example
Sometimes, client only has interface, need to download class implementation from server. In this case, we need to write our own class loader.
There are 2 ways:
1. In client side, if our class loader has not loaded this class, open a socket to server and read class binary from server. This requires server has server socket to listen connection, and return class binary.
package org.codeexample.classloader.client;
public class NetworkClassLoader extends ClassLoader {
private String host;
private int port;
public NetworkClassLoader(String host, int port) {
super();
this.host = host;
this.port = port;
}
public Class findClass(String className) {
Class result = this.findLoadedClass(className);
if (result != null) {
return result;
}
byte[] b = loadClassData(className);
return defineClass(className, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// create a connection and load the class binary from remote machine
return null;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public static void main(String[] args) throws Exception {
ClassLoader classLoader = new NetworkClassLoader("host", 8080);
Class clazz = Class.forName("invalid", false, classLoader);
Object o = clazz.newInstance();
System.err.println(o);
}
}
2. Another way is that, after server accepts a connection, as a last step, server would return a map which stores binary of all classes client needed.
2.Client would save the map and our class loader would use the map to load remote class binary.
package org.codeexample.classloader.client;
public class NetworkClassLoader2 extends ClassLoader {
private Map codeBytes = new HashMap();
protected Class findClass(String className) throws ClassNotFoundException {
Class result = this.findLoadedClass(className);
if (result != null) {
return result;
}
if (codeBytes.containsKey(className)) {
byte[] code = (byte[]) codeBytes.get(className);
return defineClass(className, code, 0, code.length);
} else {
throw new ClassNotFoundException("Unable to find class "
+ className);
}
}
public Map getCodeBytes() {
return codeBytes;
}
/**
* At the last step, server return code binary, client would call this and
* save this binary
*
* @param codeBytes
*/
public void setCodeBytes(Map codeBytes) {
this.codeBytes = codeBytes;
}
public static void main(String[] args) throws Exception {
ClassLoader classLoader = new NetworkClassLoader2();
// Class clazz = classLoader.loadClass("invalid"); //
// NetworkClassLoader2.class.getName()
// Object o = clazz.newInstance();
// System.err.println(o);
Class clazz = Class.forName("invalid", false, classLoader);
Object o = clazz.newInstance();
System.err.println(o);
}
}
The following is the code that server uses to read class binary.
package org.codeexample.classloader.server;
public class CodeSourceHolder {
private static HashSet classes = new HashSet();
public static void addClass(Class clazz) {
classes.add(clazz);
}
public static void main(String[] args) {
addClass(CodeSourceHolder.class);
Map map = getCodeBytes();
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
String clazz = (String) it.next();
byte[] classBytes = (byte[]) map.get(clazz);
System.out.println(clazz + ", class bytes[" + classBytes.length
+ "]");
}
}
public static Map getCodeBytes() {
Map map = new HashMap();
Iterator it = classes.iterator();
while (it.hasNext()) {
try {
Class type = (Class) it.next();
map.put(type.getName(), getCodeBytes(type));
} catch (IOException e) {
e.printStackTrace();
}
}
return map;
}
private static byte[] getCodeBytes(Class clazz) throws IOException {
String name = clazz.getName();
int lastPoint = name.lastIndexOf('.');
if (lastPoint != -1)
name = name.substring(lastPoint + 1);
String resource = name + ".class";
InputStream is = null;
try {
is = clazz.getResourceAsStream(resource);
byte[] codeSource = new byte[is.available()];
is.read(codeSource, 0, codeSource.length);
return codeSource;
} finally {
if (is != null) {
is.close();
}
}
}
}
The following is sample code to demonstrate how to use class loader.
package org.codeexample.classloader;
public class ClassLoaderExample {
public static void testURLClassLoader(String className) throws Exception {
URLClassLoader loader = new URLClassLoader(new URL[] { new URL(
"http://www.codeexample.com/classes/") });
Class c = loader.loadClass(className);
Object o = c.newInstance();
}
public static void testLoadLocalClass(String className) throws Exception {
URLClassLoader loader = new URLClassLoader(new URL[] { new URL(
"file://D:/ws/my-java/bin/") });
Class c = loader.loadClass(className);
Object o = c.newInstance();
// InterfaceA a = (InterfaceA) o;
// System.err.println(a.helloWorld());
}
public static void testContextLocalClass(String className) throws Exception {
String url = "some URL";
ClassLoader previous = Thread.currentThread().getContextClassLoader();
// Create a class loader using the URL as the codebase
// Use previous as parent class loader to maintain current visibility
ClassLoader current = URLClassLoader.newInstance(new URL[] { new URL(
url) }, previous);
Thread.currentThread().setContextClassLoader(current);
}
}