问题描述:
由于历史原因,系统采用了很早期的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);
}
}
}
兼容新旧POI版本
为了解决系统中旧版POI与新版不兼容的问题,本文介绍了一种通过自定义类加载器实现在同一系统中共存的方法。该方案允许新增功能使用最新版本的POI,同时确保现有功能不受影响。
757





