线程上下文加载器(ThreadContextLoad)
任意一个继承了ClassLoader的类都可以被设置为线程上下文加载器.
通过以下函数
Thread.currentThread().setContextClassLoader(myThreadLoader);
作用
这是最好玩的地方
如果一个类无法被系统加载器加载,那么就会尝试使用线程上下文加载器进行加载.
通过反射可以很容易的加载到一个类,但如果这个类依赖了其他不再当前系统加载器加载范围中的类,那么这个类实际上的用处是很单一的.
通过线程上下文加载器的使用,可以定义一个从网络中获取class的加载器,例如可以专门有一个发现类的服务,可以通过http接口按全限定名找到一个类的字节流.然后用这个接口实现依赖加载,那么程序包甚至可以没有任何非必要的包,甚至可以只要jre的包,然后就可以实现各种业务.而如果升级功能,也许只需要重启应用即可.
一个实例
public class ClassLoaderTest {
static class MyThreadLoader extends ClassLoader {
String path = "d://clazzs//";//将需要加载的类放在这个位置,包则为文件夹
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
name=name.replace(".","/");
byte[] load = load(name);
if (load.length == 0)
throw new ClassNotFoundException(name);
return defineClass( name.replace("/", "."), load, 0, load.length);
}
byte[] load(String name) {
System.out.println("--------load "+name);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (FileInputStream inputStream = new FileInputStream(new File(path + name + ".class"))) {
int c;
while ((c = inputStream.read()) != -1) {
bytes.write(c);
}
} catch (Exception e) {
e.printStackTrace();
}
return bytes.toByteArray();
}
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, InterruptedException {
Thread thread=new Thread(()->{
MyThreadLoader myThreadLoader = new MyThreadLoader();
Thread.currentThread().setContextClassLoader(myThreadLoader);
Class<?> man = null;
try {
man = myThreadLoader.findClass("bean.Man");//需要加载的类,这个类可以依赖其他也需要加载的类
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(man);
try {
System.out.println(man.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
for (Field field : man.getFields()) {
field.setAccessible(true);
System.out.println(field.getType());
}
});
thread.start();
thread.join();
}
上面定义了一个从特点磁盘位置获取类的加载功能.虽然很简陋,但也可以发现有很多好玩的地方可以做.