问题描述:
由于历史原因,系统采用了很早期的poi,而最新的poi和之前版本并不兼容,现在要系统要增加一个新功能,需要引入最新的jar文件,在不影响已有使用的基础上,我们如何处理该问题?
解决方案:
本人的思路是写一个类加载器,动态的加载所需的jar文件到一个单独的命名空间,由于jvm默认的类加载是采用父委托机制的,但在这里,类加载器的实现思路和一些web 容器的类加载机制是一致的(如tomcat jetty等) ,即优先加载自己指定路径下的jar文件,如果加载不到所需的类文件则委托给父加载器,所以我们需重写ClassLoader的loadClass方法,最后上代码,代码很简单,但有一点比较重要,即默认java类所依赖的类是采用和该类相同的类加载器加载的
public class ParentLastClassLoader extends ClassLoader{ private String[] jarFiles; //jar文件路径 private Hashtable classes = new Hashtable(); //将定义的类缓存在hashtable里面 public ParentLastClassLoader(ClassLoader parent, String[] paths) { super(parent); this.jarFiles = paths; } @Override public Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(); } @Override protected synchronized Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { try { byte classByte[]; Class result = null; //先从缓存中查看是否已经加载该类 result = (Class) classes.get(className); if (result != null) { return result; } //如果没找到该类,则直接从jar文件里面加载 for(String jarFile: jarFiles){ try { JarFile jar = new JarFile(jarFile); JarEntry entry = jar.getJarEntry(className.replace(".","/") + ".class"); InputStream is = jar.getInputStream(entry); ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); int nextValue = is.read(); while (-1 != nextValue) { byteStream.write(nextValue); nextValue = is.read(); } classByte = byteStream.toByteArray(); if(classes.get(className) == null){ result = defineClass(className, classByte, 0, classByte.length, null); classes.put(className, result); } } catch (Exception e) { continue; } } result = (Class) classes.get(className); if (result != null) { return result; } else{ throw new ClassNotFoundException("Not found "+ className); } } catch( ClassNotFoundException e ){ return super.loadClass(className, resolve); } } }