由于项目需要动态加载,其中有两个jar需要动态加载,engine.jar, rule.jar。
engine.jar基本不变,所以,先打算把engine.jar直接放在项目里,静态加载了,再动态加载rule.jar。classloader示意如下
EngineImpl里面使用Rule里的类的时候,就出现了ClassNotFoundExceptioin。
这就奇怪了,classloader2里明明加载了Rule.jar呀,后经过多次实验,终于找到了原因:虽然我们使用classloader2(继承了classloader1)生成的EngineImpl,但是,EngineImpl是在classloader1里,所以,它查找类的时候,使用的是classloader1, 自然就找不到rule.jar里的类了。
这样问题就解决了,有两种解决方案:
1. 把engine.jar也动态加载,这样他们两个jar就在同一个classloader里了。
URL url1 = new File("./lib/engine.jar").toURI().toURL();
URL url2 = new File("./lib/rule.jar").toURI().toURL();
log.info("classloader: {}:{}", url1, url2);
URLClassLoader classLoader2 = new URLClassLoader(new URL[]{url1, url2}, this.getClass().getClassLoader());
Class<?> clz = classLoader2.loadClass("com.....EngineImpl");
Engine engine = (Engine) clz.newInstance();
Result rst = engine.exec(...);
2. 在engine使用Rule的时候,把classloader2传进去。
URL urlRule = new File("./lib/rule.jar").toURI().toURL();
URLClassLoader classLoader2 = new URLClassLoader(new URL[]{urlRule},
this.getClass().getClassLoader());
Class<?> clz = classLoader2.loadClass(“com….EngineImpl");
Engine engine = (Engine)clz.newInstance();
Result rst = engine.exec(classloader2, ….);
在EngineImpl里
public Result exec(ClassLoader classloader2, ....){
//这里要使用传进来的classloader2加载动态类P2021B311Rule
Rule rule = (Rule)classloader2.loadClass("com.....P2021B311Rule").newInstance();
rule.exec(...);
......
return reulst;
}
其它注意:
动态jar里面不要有与静态classloader冲突的类,最好是不要有重复的类。