1.java -jar 运行jar包时,javassist.ClassPool 报ClassNotFound 在完成基于javassist技术和RequestMappingHandlerMapping实现自定义|动态注册spring mvc HandlerMapping的迭代记录的开发后,部署到线上环境中时,运行提示异常:
javassist.NotFoundException: cn.yuyizyk.compent.Handler
at javassist.ClassPool.get(ClassPool.java:422) ~[javassist-3.23.1-GA.jar!/:na]
at cn.yuyizyk.compent.SrcActionAnalysis.lambda$3(SrcActionAnalysis.java:194) ~[classes!/:0.0.1-SNAPSHOT]
定位错误位置:
// cn.yuyizyk.compent.SrcActionAnalysis
CtClass handleCtClz = pool.makeClass(Handler.class.getName() + "$" + c.getSimpleName() + "$" + m.getName()+ "R" +
(new Random().nextInt(1024)),pool.get(Handler.class.getName()));
// javassist.ClassPool :561
/**
* Searches the class path to obtain the URL of the class file
* specified by classname. It is also used to determine whether
* the class file exists.
*
* @param classname a fully-qualified class name.
* @return null if the class file could not be found.
* @see CtClass#getURL()
*/
public URL find(String classname) {
return source.find(classname);
}
// 然后通过反射定位到 javassist.ClassClassPath 91
/**
* Obtains the URL of the specified class file.
*
* @return null if the class file could not be found.
*/
@Override
public URL find(String classname) {
String filename = '/' + classname.replace('.', '/') + ".class";
return thisClass.getResource(filename);// 此处的thisClass : Object.class
}
// 根据java.lang.Class:2265 Object.class.getClassLoader() is null
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
//java.lang.Class:1226
public static URL getSystemResource(String name) {
ClassLoader system = getSystemClassLoader();
if (system == null) {
return getBootstrapResource(name);
}
return system.getResource(name);
}
因此问题是SystemClassLoader加载cn.yuyizyk.compent.Handler.class 失败。
此后,我打印java.class.path 也佐证了这一点:
System.out.println(System.getProperty("java.class.path"));
// TODO main start print
D:\2.git\notes\notes\spring-dynamic-handlerMapping\target\classes;...
// TODO spring jar start print
.\spring-dynamic-handlerMapping-0.0.1-SNAPSHOT.jar
基本可以确定问题便是SystemClassLoader加载路径不一致导致classNotFound。
这个问题从何而来? 当把项目打包为jar包运行是,java -jar 会把其他classpath给屏蔽,只使用jar包的classpath.即.\spring-dynamic-handlerMapping-0.0.1-SNAPSHOT.jar,因此无法正确查找class。
解决方案 将当前ClassPath 注册到javassist 的ClassPath中即可。
ClassPool.getDefault().appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
// TODO 同时注意在生成javassist CtClass -> Class时,加载的classloader不能是SystemClassLoade,原因亦如。
来源:oschina
链接:https://my.oschina.net/u/3632223/blog/2994202