1.java -jar 运行jar包时,javassist.ClassPool 报ClassNotFound 在完成基于javassist技术和RequestMappingHandlerMapping实现自定义|动态注册spring mvc HandlerMapping的迭代记录的开发后,部署到线上环境中时,运行提示异常:java
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]
定位错误位置:git
// 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 失败。spring
此后,我打印java.class.path 也佐证了这一点:mvc
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。app
这个问题从何而来? 当把项目打包为jar包运行是,java -jar 会把其余classpath给屏蔽,只使用jar包的classpath.即.\spring-dynamic-handlerMapping-0.0.1-SNAPSHOT.jar,所以没法正确查找class。dom
解决方案 将当前ClassPath 注册到javassist 的ClassPath中便可。ide
ClassPool.getDefault().appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader())); // TODO 同时注意在生成javassist CtClass -> Class时,加载的classloader不能是SystemClassLoade,缘由亦如。