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,緣由亦如。