有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

scala(jar)库的java着色依赖项

我想分发我创建的一个库的一个罐子,里面捆绑了我的所有依赖项。然而,我希望避免与采用项目的依赖项的版本冲突

我认为maven shade可以做到这一点,但我找不到使用Scala/SBT实现这一点的方法。然而,我在实验中发现OneJar似乎只对可执行文件有效

我怎样才能做到这一点

谢谢


共 (3) 个答案

  1. # 1 楼答案

    你可以用自己的类加载器来实现

    类加载器:
    编写一个类加载器,使用重写从不同的类加载器加载类文件

    例如,在获取资源时,可以将库作为前缀添加到类路径中

    我用这个技术创建了一个类加载器。 https://github.com/espenbrekke/dependent/blob/master/src/main/java/no/dependent/hacks/PathRewritingClassLoader.java

    它用添加前缀的方法替换URLClassLoader中的findClass方法

    protected Class<?> findClass(final String name) throws ClassNotFoundException {
        Class result;
        try {
            result = (Class)AccessController.doPrivileged(new PrivilegedExceptionAction() {
                public Class<?> run() throws ClassNotFoundException {
    
    // This is where the prefix is added:
                    String path = PathRewritingClassLoader.this.prefix + name.replace('.', '/').concat(".class");
                    Resource res = PathRewritingClassLoader.this._ucp.getResource(path, false);
                    if(res != null) {
                        try {
                            return PathRewritingClassLoader.this._defineClass(name, res);
                        } catch (IOException var4) {
                            throw new ClassNotFoundException(name, var4);
                        }
                    } else {
                        return null;
                    }
                }
            }, this._acc);
        } catch (PrivilegedActionException var4) {
            throw (ClassNotFoundException)var4.getException();
        }
    
        if(result == null) {
            throw new ClassNotFoundException(name);
        } else {
            return result;
        }
    }
    

    我们还必须重写资源加载

    @Override
    public URL getResource(String name){
        return super.getResource(prefix+name);
    }
    

    下面是它的用法:

    _dependentClassLoader = new PathRewritingClassLoader("private", (URLClassLoader)DependentFactory.class.getClassLoader());
    Class myImplementationClass=_dependentClassLoader.loadClass("my.hidden.Implementation");
    

    构建你的罐子:
    在构建中,将所有库和私有类放置在所选前缀下。在我的gradle构建中,我有一个简单的循环来收集所有依赖项

    task packageImplementation {
    dependsOn cleanImplementationClasses
    
    doLast {
        def paths = project.configurations.runtime.asPath
        paths.split(':').each { dependencyJar ->
            println "unpacking" + dependencyJar
    
            ant.unzip(src: dependencyJar,
                    dest: "build/classes/main/private/",
                    overwrite: "true")
            }
        }
    }
    
  2. # 2 楼答案

    你试过sbt-assembly插件吗?它有一套在发生冲突时的合并策略,并且有非常好的开始指南