从servlet加载不同版本的jar库



我有几个第三方jar将被我的webapps使用。这些JAR文件实际上有不同的版本。

1.0版本jar

  • /opt/lib/third-party-jars/1.0/3rdparty1.jar
  • /opt/lib/third-party-jars/1.0/3rdparty2.jar

Version 2.0 JARs

  • /opt/lib/third-party-jars/2.0/3rdparty1.jar
  • /opt/lib/third-party-jars/2.0/3rdparty2.jar

是否有可能在servlet加载之前动态加载不同版本的库?是否有任何框架能够做到这一点,而不改变我现有的代码?

public class Servlet1 extends HttpServlet {
    protected void doPost(....) {
        MyBusinessLogic businessLogic = new MyBusinessLogic();
        businessLogic.run() // My business logic spawns here which will start involving third-party classes 
    }
}

或者是否可以在调用业务逻辑之前在代码中动态加载1.0或2.0版本库?我能想到的一种方法是使用自定义类加载器和"setContextClassLoader",但这需要使用反射重构所有业务逻辑。这将是一项巨大的努力。我试图不改变我现有的业务逻辑代码。

Java不支持同一jar的多个版本。两个选择:

  • 扩展tomcat的类加载器以提供自定义加载逻辑
  • 使用OSGi。Virgo是基于osgi的servlet容器

然而,这两种方法都会使事情不必要地复杂化。我建议引入某种由多个提供者实现的SPI。所以:

public interface BusinessLogic { .. }

然后是两个jar,有两个实现——com.foo.FooBLcom.bar.BarBL。然后配置需要哪一个,并使用Class.forName(..).newInstance(..)

实例化它

一般来说,您想要的是非常困难的:servlet容器已经包含了复杂的类加载器层次结构,并且试图在适当的位置混合另一个通常会导致不必要的痛苦,应该避免。但是,看看JCL:它可以做您想做的事情。

据我所知,您无法控制使用哪个类加载器来加载web.xml中定义的servlet。

在JavaEE 6中,您可以使用ServletContext.addServlet()来添加一个servlet,它的类是您从自己的类加载器中获得的。所以你可以有一个虚拟的'bootstrap' servlet(或监听器或过滤器-只要它在启动时加载):

  • 使用适当版本的jar创建自定义类加载器
  • 从你的自定义类加载器创建你的真正的 servlet类(这个servlet类不应该在web.xml中指定)
  • 使用ServletContext.addServlet()
  • 注册这个类

我在这里完全脱离了规范,我还没有测试过,不知道它是否真的能工作

正如其他几个人已经提到的,做你所建议的远非微不足道。进一步解释为什么需要加载不同版本的jar,以及触发此决定的条件是什么,可能会对您有所帮助。理解这一点可能会帮助其他人想出一个不同的解决方案来解决你的问题。

例如,是否有可能为每个版本创建多个WAR或EAR程序集,并在WAR/EAR中捆绑相应的第三方jar ?在独立的WAR/EAR中捆绑第三方jar将确保您所寻找的类装入器可见性。这应该不需要太多/任何新的编码,只是一些重组。或者,如果捆绑第三方jar不是一个选项,并且您使用的是WAS之类的应用服务器,那么您可能会利用共享库,以便您的一个war引用1.0版本的jar,而另一个引用2.0版本。

最新更新