如何让ColdFusion加载指定文件夹最新Jar而非lib目录旧版本
解决ColdFusion 10中优先加载指定版本BouncyCastle的方案
我太懂你这种头疼的感受了——ColdFusion 10的lib目录里的旧版BouncyCastle总像个“插队者”,抢在你指定的新版本之前被加载,哪怕你打包了带类路径的门面Jar也没用。这本质是ColdFusion的类加载机制导致的:系统类加载器会优先加载lib目录下的Jar,而默认类加载器遵循双亲委派模型,会先让父加载器(也就是系统加载器)尝试加载类,自然就拿到旧版本了。
下面是几个经过验证的解决办法,按可行性排序:
1. 自定义类加载器打破双亲委派
这是最可靠的方案,直接绕过系统加载器优先加载你的新版本Jar:
步骤1:编写自定义类加载器
先写一个简单的Java类加载器,强制优先从你指定的BouncyCastle Jar加载类,只有当找不到核心系统类时才委托给系统加载器:
import java.net.URL; import java.net.URLClassLoader; public class BcPriorityClassLoader extends URLClassLoader { public BcPriorityClassLoader(URL[] urls) { super(urls, null); // 将父加载器设为null,打破双亲委派 } @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 先检查是否已加载过该类 Class<?> loadedClass = findLoadedClass(name); if (loadedClass == null) { try { // 优先从自己的Jar中查找类 loadedClass = findClass(name); } catch (ClassNotFoundException e) { // 核心系统类交给系统加载器处理 loadedClass = ClassLoader.getSystemClassLoader().loadClass(name); } } if (resolve) { resolveClass(loadedClass); } return loadedClass; } }
把这个类编译后,和你的新版本BouncyCastle Jar放在同一个目录(或者打包进你的门面Jar里)。
步骤2:在ColdFusion中使用自定义加载器
在CFML代码里初始化这个加载器,加载新版本的BouncyCastle Provider,然后替换掉旧的Provider:
<!--- 指定你的新版本BouncyCastle Jar路径 ---> <cfset newBcJarPath = "C:\path\to\your\bcprov-jdk15on-1.70.jar"> <!--- 创建Jar的URL对象 ---> <cfset jarFile = createObject("java", "java.io.File").init(newBcJarPath)> <cfset jarURL = jarFile.toURI().toURL()> <!--- 初始化自定义类加载器 ---> <cfset classLoader = createObject("java", "com.yourpackage.BcPriorityClassLoader").init([jarURL])> <!--- 加载新版本的BouncyCastle Provider类 ---> <cfset bcProviderClass = classLoader.loadClass("org.bouncycastle.jce.provider.BouncyCastleProvider")> <cfset newBcProvider = bcProviderClass.newInstance()> <!--- 移除旧版本的BC Provider(如果已注册) ---> <cfset security = createObject("java", "java.security.Security")> <cfset oldProvider = security.getProvider("BC")> <cfif isDefined("oldProvider") and oldProvider neq ""> <cfset security.removeProvider("BC")> </cfif> <!--- 将新版本Provider添加到最优先位置 ---> <cfset security.addProviderAt(newBcProvider, 1)>
这样后续所有邮件加密相关的操作都会使用你指定的新版本BouncyCastle了。
2. 临时调整ColdFusion的类加载路径(无Application.cfc版本)
如果不想写自定义加载器,你可以尝试在单个页面中通过<cfapplication>标签临时指定类加载路径,强制优先加载你的新版本Jar:
<cfapplication name="TempBcLoader" javaSettings="{ loadPaths: ['C:\path\to\your\new\bc.jar'], reloadOnChange: true, loadColdFusionClassPath: false }" >
这里的loadColdFusionClassPath: false会让ColdFusion先从你指定的路径加载类,而不是优先用系统lib目录。不过这个方法的局限性是:它只对当前请求生效,而且如果其他页面没有设置,还是会用旧版本。
注意事项
- 确保你的自定义加载器只加载BouncyCastle相关的类,不要覆盖系统核心类,否则会引发其他问题。
- 如果你的加密代码是封装在门面Jar里的,要确保门面类也是通过这个自定义加载器加载的,避免出现类加载不一致的错误。
- 测试时记得重启ColdFusion,清除之前加载的旧版本类缓存。
内容的提问来源于stack exchange,提问作者michel
相关产品推荐
相关产品推荐

