问题描述
我想分发一个我创建的库的jar,其中包含所有依赖项。但是,我想避免与采用项目的依赖项版本冲突。
I would like to distribute a jar of a library I created with all my dependencies bundled inside. However I would like to avoid version conflicts of dependencies with the adopting project.
我认为maven shade可以做到这一点,但我找不到用Scala做到这一点的方法/ SBT。我发现OneJar但是我的实验似乎只适用于可执行文件。
I think maven shade can do this but I could not find a way to do this with Scala / SBT. I found OneJar however from my experiments with it seems to work only for executables.
我怎么能实现这个目标?
How could I achieve this?
谢谢!
推荐答案
您可以使用自己的类加载器执行此操作。
You can do this with your own classloader.
classLoader:
编写一个类加载器,它使用重写从不同的类加载器加载类文件。
The classLoader:
Write a class loader which loads class files from diferent classloader using a rewrite.
例如,您可以在获取资源时将库添加为类路径的前缀。
For example you could add library as a prefix to the classpath when fetching the resource.
我创建了使用此teqnuiqe的类加载器。
I have created a classloader using this teqnuiqe.https://github.com/espenbrekke/dependent/blob/master/src/main/java/no/dependent/hacks/PathRewritingClassLoader.java
它用一个添加前缀的URLClassLoader替换方法findClass。
It replaces the method findClass in URLClassLoader with one adding a prefix.
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;
}
}
我们还必须重写资源加载
We also have to rewrite resource loading
@Override
public URL getResource(String name){
return super.getResource(prefix+name);
}
以下是它的使用方法:
Here is how it is used:
_dependentClassLoader = new PathRewritingClassLoader("private", (URLClassLoader)DependentFactory.class.getClassLoader());
Class myImplementationClass=_dependentClassLoader.loadClass("my.hidden.Implementation");
建立你的jar:
在你的构建中您将所有库和私有类放在所选前缀下。在我的gradle构建中,我有一个简单的循环收集所有依赖项。
Building your jar:
In your build you place all the library and private classes under your selected prefix. In my gradle build I have a simple loop collecting all the dependencies.
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")
}
}
}
这篇关于着色scala(jar)库的依赖关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!