修改Apache Velocity源码并重新打包velocity1.7.jar已解决动态加载自定义函数的问题(二)
上文链接:https://blog.csdn.net/rico_zhou/article/details/105008066
这一篇我们讲述如何修改velocity源码并打包:
首先下载源码:http://archive.apache.org/dist/velocity/engine/1.7/,需要两个文件一个是pom,一个是zip:
velocity-1.7.pom,velocity-1.7.zip
由于项目是ant构建,我们现在改成maven项目导入开发工具中,然后在使用ant打包,
首先将velocity-1.7.zip解压到velocity-1.7,然后将velocity-1.7.pom复制到根目录下并修改文件为pom.xml,然后使用eclipse或者idea以maven项目导入velocity-1.7,等待加载完成,报错的话百度即可解决,注意velocity项目比较老,使用的jdk也比较老。
然后我们开始修改源码,找到类:org.apache.velocity.runtime.RuntimeInstance,定位到1000行左右这个方法附近:
/** * instantiates and loads the directive with some basic checks * * @param directiveClass classname of directive to load */ public void loadDirective(String directiveClass) { try { Object o = ClassUtils.getNewInstance( directiveClass); if (o instanceof Directive) { Directive directive = (Directive) o; addDirective(directive); } else { String msg = directiveClass + " does not implement " + Directive.class.getName() + "; it cannot be loaded."; log.error(msg); throw new VelocityException(msg); } } // The ugly threesome: ClassNotFoundException, // IllegalAccessException, InstantiationException. // Ignore Findbugs complaint for now. catch (Exception e) { String msg = "Failed to load Directive: " + directiveClass; log.error(msg, e); throw new VelocityException(msg, e); } }
修改成如下
/** * instantiates and loads the directive with some basic checks * * @param directiveClass classname of directive to load */ public void loadDirective(String directiveClass) { try { //Modify the source code here to add a parameter to read additional jars String[] extraJarPathArr=configuration.getStringArray("extrauserdirective"); Object o = ClassUtils.getNewInstance( directiveClass ,extraJarPathArr); if (o instanceof Directive) { Directive directive = (Directive) o; addDirective(directive); } else { String msg = directiveClass + " does not implement " + Directive.class.getName() + "; it cannot be loaded."; log.error(msg); throw new VelocityException(msg); } } // The ugly threesome: ClassNotFoundException, // IllegalAccessException, InstantiationException. // Ignore Findbugs complaint for now. catch (Exception e) { String msg = "Failed to load Directive: " + directiveClass; log.error(msg, e); throw new VelocityException(msg, e); } }
添加并修改这个:
//Modify the source code here to add a parameter to read additional jars String[] extraJarPathArr=configuration.getStringArray("extrauserdirective"); Object o = ClassUtils.getNewInstance( directiveClass ,extraJarPathArr);
传递一个参数,这个参数传递的是需要加载的自定义函数jar的位置,可以是目录或者jar路径,目录则扫码其下首页jar,然后重载方法ClassUtils.getNewInstance(),
定位到类:org.apache.velocity.util.ClassUtils,大概180行,重载方法:尽量减少影响,所以方法都重载而不是覆写
public static Object getNewInstance(String clazz) throws ClassNotFoundException,IllegalAccessException,InstantiationException { return getClass(clazz).newInstance(); } //Modify the source code here to add a parameter to read additional jars public static Object getNewInstance(String clazz,String[] extraJarPathArr) throws ClassNotFoundException,IllegalAccessException,InstantiationException { return getClass(clazz,extraJarPathArr).newInstance(); }
再次重载getClass方法:
/** * Return the specified class. Checks the ThreadContext classloader first, * then uses the System classloader. Should replace all calls to * <code>Class.forName( claz )</code> (which only calls the System class * loader) when the class might be in a different classloader (e.g. in a * webapp). * * @param clazz the name of the class to instantiate * @return the requested Class object * @throws ClassNotFoundException */ public static Class getClass(String clazz) throws ClassNotFoundException { return getClass(clazz,null); } //Modify the source code here to add a parameter to read additional jars public static Class getClass(String clazz,String[] extraJarPathArr) throws ClassNotFoundException { /** * Use the Thread context classloader if possible */ ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) { try { return Class.forName(clazz, true, loader); } catch (ClassNotFoundException E) { /** * If not found with ThreadContext loader, fall thru to * try System classloader below (works around bug in ant). */ if (extraJarPathArr != null) { List allFileList = new ArrayList(); for (int i=0;i<extraJarPathArr.length;i++) { String path=extraJarPathArr[i]; if (path != null) { File p = new File(path); if (p.exists()) { if (p.isDirectory()) { File[] pp = p.listFiles(); List flist = filterFile(pp, ".jar"); allFileList.addAll(flist); } else if (p.isFile() && p.getAbsolutePath().endsWith(".jar")) { allFileList.add(p); } } } } for (int i=0;i<allFileList.size();i++) { File f=(File) allFileList.get(i); URL u; try { u = listFileByPluginName(f); ClassLoader classLoader = new URLClassLoader(new URL[] { u }, Thread.currentThread().getContextClassLoader()); return classLoader.loadClass(clazz); } catch (Exception e) { } } } } } /** * Thread context classloader isn't working out, so use system loader. */ return Class.forName(clazz); }
再加一个工具方法:
public static List filterFile(List resultFile, String fileExtensionPointFileVm) { List filterFileList = new ArrayList(); if (resultFile != null && resultFile.size() > 0) { for (int i=0;i<resultFile.size();i++) { File f=(File) resultFile.get(i); if (f.isFile() && f.getAbsolutePath().endsWith(fileExtensionPointFileVm)) { filterFileList.add(f); } } } return filterFileList; } public static List filterFile(File[] resultFile, String fileExtensionPointFileVm) { List filterFileList = new ArrayList(); if (resultFile != null && resultFile.length > 0) { for (int i=0;i<resultFile.length;i++) { File f=resultFile[i]; if (f.isFile() && f.getAbsolutePath().endsWith(fileExtensionPointFileVm)) { filterFileList.add(f); } } } return filterFileList; } private static URL listFileByPluginName(File jar) throws Exception { if (!jar.exists()) { throw new RuntimeException("Not found JAR: " + jar.getName()); } URL url = jar.toURI().toURL(); return url; }
注意不能有中文,不能使用泛型(比较老没办法,尽量不动原来打包方式)
方法也比较简单,基本就是使用当前线程类加载器加载自定义函数类,失败的话则使用修改的方法加载,即根据传递的参数去jar目录扫描目录下所有jar(不包括子目录),多个目录传递的参数以逗号间隔,子目录不遍历防止内容态度耗时,然后使用
ClassLoader classLoader = new URLClassLoader(new URL[] { u }, Thread.currentThread().getContextClassLoader());
方式加载类,如果失败则再使用源码中写的系统类加载器。
修改完成后我们准备打包:
首先下载ant:http://ant.apache.org/bindownload.cgi,最新版本zip,解压并添加环境变量ANT_HOME,打开命令行输入ant回车有反应即可。
到根目录下(项目根目录),将lib中的jar包复制到bin/lib下,lib/test下jar复制到/bin/test-lib下,然后进入build目录,打开命令执行ant,等待打包完成,报错则解决,然后查看bin目录下有velocity-1.7.jar,这个就是修改后的jar,可以看到大小约440k,与原有jar差不多大小。
接下来将jar引入到软件项目中,初始化引擎时传递需要加载的自定义jar路径和类名:
自定义函数类名加载:
p.setProperty("userdirective", "com.soft.support.velocity.custom.NowDate");
需要加载的额外参数:
p.setProperty("extrauserdirective", "D:/test/test");
在模板中调用NowDate这个方法就成功啦!
原网址: 访问
创建于: 2023-08-07 10:03:52
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论