扩展类加载器-------改变JAVA的父优先类加载顺序
java的类加载机制默认情况下是采用委托模型:当加载某个类时JVM会首先尝试用当前类加载器的父类加载器加载该类,若父类加载器加载不到再由当前类加载器来加载,因此这种模型又叫做“父优先”模型。
但是在实际项目中我们可能会要求先从当前类加载加载再从父类加载器加载,如项目中的某类的版本可能和container中的不一致的时候,若还从 container加载就会报jar包冲突的异常,实际上jar包冲突的问题在实际开发过程中是经常会遇到的。如我们在开发Loong时就遇到了类似问 题。
解决方案是通过扩展自定义的ClassLoader,重写loadClass方法,先从当前类加载器加载再从父类加载器加载。
public class MCFClassLoader extends URLClassLoader {
/**
* @param urls
*/
public MCFClassLoader(URL[] urls) {
super(urls);
}
/**
* @param urls
* @param parent
*/
public MCFClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
/**
* @param urls
* @param parent
* @param factory
*/
public MCFClassLoader(URL[] urls, ClassLoader parent,
URLStreamHandlerFactory factory) {
super(urls, parent, factory);
}
/*
* (non-Javadoc)
*
* @see java.lang.ClassLoader#loadClass(java.lang.String)
*/
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
c = findClass(name);
} catch (ClassNotFoundException e) {
return super.loadClass(name);
}
}
return c;
}
}
通过上面的ClassLoader就解决了我们遇到的问题。
思考:通过扩展URLClassLoader可以实现好多有趣的功能,如支持多父、支持加载顺序配置等等。
作为补充给出一个使用上面的ClassLoader的示例代码:
File bundleFile = new File(
"D:\\IDE\\UTMP-Studio-2.0\\workspace\\utmp.code.coverage.test.7_1\\lib\\UTMP",
"STAR-1.0.jar");
if (!bundleFile.exists()) {
throw new FileNotFoundException(bundleFile.getAbsolutePath());
}
// 加载star.jar
URL m_osgiFilePathName = bundleFile.toURI().toURL();
MCFClassLoader urlClassLoader = new MCFClassLoader(
new URL[] { m_osgiFilePathName },
AssetWizardSrvImplTest.class.getClassLoader());
Method method = URLClassLoader.class.getDeclaredMethod("addURL",
URL.class);
Boolean methodAccessible = method.isAccessible();
method.setAccessible(true);
method.invoke(urlClassLoader, m_osgiFilePathName);
method.setAccessible(methodAccessible);