java的类加载机制默认情况下是采用委托模型:当加载某个类时JVM会首先尝试用当前类加载器的父类加载器加载该类,若父类加载器加载不到再由当前类加载器来加载,因此这种模型又叫做“父优先”模型。
但是在实际项目中我们可能会要求先从当前类加载加载再从父类加载器加载,如项目中的某类的版本可能和container中的不一致的时候,若还从container加载就会报jar包冲突的异常,实际上jar包冲突的问题在实际开发过程中是经常会遇到的。如我们在开发Loong时就遇到了类似问题。
解决方案是通过扩展自定义的ClassLoader,重写loadClass方法,先从当前类加载器加载再从父类加载器加载。
public class MCFClassLoader extends URLClassLoader { public MCFClassLoader(URL[] urls) { super(urls); } public MCFClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } public MCFClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { super(urls, parent, factory); } 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的示例代码:
上面的例子说明当xxx.jar或yyy.jar中有需要加载的类时就从这些jar包里加载,即使所在的container里有同样的类,这样可在一定程度上避免jar包版本冲突的问题!