简体   繁体   English

将第三方API集成到具有冲突依赖关系的Java应用程序中

[英]Integrating a third-party API into a Java application with clashing dependencies

I am working on an existing application which has quite a lot of external JAR dependencies. 我正在开发一个现有的应用程序,它具有相当多的外部JAR依赖项。 I need to enhance it to integrate with a third-party application which has an API. 我需要增强它以与具有API的第三方应用程序集成。 Sadly, the API is not well contained and also comes with a large number of its own dependencies some of which clash with mine. 可悲的是,API并没有得到很好的控制,并且还附带了大量自己的依赖项,其中一些依赖于我的。

I believe I should solve this using Classloaders, but I'm struggling to see how to structure them correctly. 我相信我应该使用类加载器解决这个问题,但我很难看到如何正确地构造它们。

To keep it simple, assume we have myapp.jar with a hibernate3.jar dependency, and vendor-api.jar with a hibernate2.jar dependency (and assume these are incompatible). 为了简单起见,假设我们的myapp.jar具有hibernate3.jar依赖性,而vendor-api.jar具有hibernate2.jar依赖性(并假设它们不兼容)。

My new piece of code will reside in the myapp.jar library (although it could be in a separate jar if this would help). 我的新代码将驻留在myapp.jar库中(尽管如果这会有帮助,它可能在一个单独的jar中)。 Due to the way the vendor API works, my new code needs to extend a class from the vendor-api.jar library. 由于供应商API的工作方式,我的新代码需要从vendor-api.jar库扩展一个类。

How can I structure the Classloaders in such a way that anything within the vendor-api.jar accesses only its own dependencies, and anything on my side accesses only the myapp.jar and dependencies? 如何以这样的方式构造类加载器:vendor-api.jar中的任何东西只访问它自己的依赖项,而我这边的任何东西只访问myapp.jar和依赖项?

Thanks, Jon 谢谢,乔恩

I've not tried this myself, but from memory each clashing class needs to be in a sibling classloader and any communication between the two needs to go through a common ancestor. 我自己没有尝试过这个,但是从内存中来看,每个冲突类都需要在一个兄弟级的类加载器中,并且两者之间的任何通信都需要经历一个共同的祖先。 However, the ancestor cannot (AFAIK) "directly" reference classes from its children and must access them through the reflection API. 但是,祖先不能(AFAIK)“直接”引用其子类中的类,并且必须通过反射API访问它们。

Something along these lines ought to work (dry-coded) YMMV. 沿着这些方向的东西应该起作用(干编码)YMMV。 Comments and error-spotting welcome. 评论和错误发现欢迎。

class Orchestrator {
    URL[] otherAppClasspath = new URL[] { new URL("file:///vendor-api.jar"),
                                          new URL("file:///hibernate2.jar"),
                                          new URL("file:///code-extending-vendor-api.jar" };
    URLClassLoader otherAppLoader = new URLClassLoader(otherAppClasspath);

    URL[] yourAppClasspath = new URL[] { new URL("file:///myapp.jar"),
                                         new URL("file:///hibernate3.jar") };
    URLClassLoader yourAppLoader = new URLClassLoader(yourAppClasspath);

    public void start() {
        Method yourAppEntryPoint = yourAppLoader.findClass("com/company/Main").getMethod("start", new Class[] { Orchestrator.class } );
        yourAppEntryPoint.invoke(null, new Object[] { this });
    }

    public static void main(String[] args) {
        new Orchestrator().start();
    }

    // define some abstracted API here that can be called from your app
    // and calls down into classes in the other app
    public String getSomeResultFromOtherApp(int someArgument) {
        Method otherAppAPI = otherAppLoader.findClass("com/company/ExtendingAPIClass").getMethod("getSomeResult", new Class[] { Integer.class });
        return (String)otherAppAPI.invoke(null, new Object[] { someArgument });          
    }

}

@fd's answer gives a technical mechanism that ought to work - give or take some typos, exception handling, etc. @ fd的答案提供了一个应该工作的技术机制 - 给予或采取一些拼写错误,异常处理等。

However, I think you would be better off not trying to do this ... unless your dependencies on the 3rd party APIs are restricted to a very small number of methods on a very small number of classes. 但是,我认为最好不要尝试这样做...除非你对第三方API的依赖仅限于极少数类的极少数方法。 Each class that you depend on has to be dynamically loaded and each method has to be looked up and invoked reflectively. 您依赖的每个类都必须动态加载,并且必须以反射方式查找和调用每个方法。 Too much of that and your codebase will suffer. 太多,你的代码库将受到影响。

If I were you, I'd try to resolve the dependency issue some other way: 如果我是你,我会尝试以其他方式解决依赖问题:

  1. Try to get the 3rd party vendor to use hibernate3.jar 尝试让第三方供应商使用hibernate3.jar
  2. Change your application to use hibernate2.jar 将您的应用程序更改为使用hibernate2.jar
  3. Refactor so that your application code and the 3rd party library are in separate JVMs or separate webapps. 重构,以便您的应用程序代码和第三方库位于单独的JVM或单独的Web应用程序中。

From what you say, this might be hard. 从你说的话来看,这可能很难。

Using OSGi may help you in the long term. 使用OSGi可以长期帮助您。 Here is an implementation I am trying now- http://felix.apache.org 这是我正在尝试的实现 - http://felix.apache.org

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 维护第三方Java库依赖项的补丁 - Maintaining patches of third-party Java library dependencies Java 中的第三方 API 包装器:如何设计 - Third-party API wrapper in Java: how to design Gradle Compile & Execute the Single Java Class with third-party jar dependencies using Gradle `buildscript` - Gradle Compile & Execute the Single Java Class with third-party jar dependencies using Gradle `buildscript` Java - 如何减小第三方jar的大小以减小应用程序的大小 - Java - How to reduce the size of third-party jars to reduce the size of your application 是否可以在第三方Android应用程序中调试类? - Is it possible to debug classes in a third-party Android application? Android:获取第三方应用标签,部分标签异常 - Android: Get third-party application label, some labels are abnormal Android Studio:根据第三方库的来源制作应用程序 - Android Studio: make application depending on sources of third-party library 引用在 Java 中使用第三方库的类 - reference a class that uses a third-party library in Java Java:实现hashCode并等于第三方类是否可以? - Java: Is it OK to implement hashCode and equals for a third-party class? Scala中的Akka和第三方Java库的最佳实践 - Best practices with Akka in Scala and third-party Java libraries
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM