在写插件的时候不可避免的需要调用一些外部库,我们需要把依赖打包到jar中,当使用的依赖过多时体积将非常臃肿。通过 Loading Dependencies from External Sources in Spigot这篇文章和阅读luckperms的解决方法,花了半个通宵捣鼓出了一种可行的方案
最初的解决方案是通过ClassLoader
的addURL动态的加载依赖,但就像上面那篇文章说的,java16以上的反射不允许这样的操作;最后我找到了这个仓库 https://github.com/Revxrsal/PluginLib/tree/master/src/main/java/pluginlib
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| static { try { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); Field ucpField = URLClassLoader.class.getDeclaredField("ucp"); ucp = unsafe.getObject(AifadianPay.class.getClassLoader(), unsafe.objectFieldOffset(ucpField)); Field lookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(lookupField), unsafe.staticFieldOffset(lookupField)); addUrlHandle = lookup.findVirtual(ucp.getClass(), "addURL", MethodType.methodType(void.class, URL.class)); } catch (Exception e) { throw new RuntimeException(e); } }
|
它使用Unsafe绕过安全检查,像魔法一样的取得了 addURL
方法,经过测试,在jdk8到17的版本都运行良好。
这是一个最后更新于2020年的库,我去除了一些无用的功能(对我来说),整理到了https://github.com/meteorOSS/SpigotDependencyManager
接下来,示范一下使用这个新工具来写代码
首先下载上方git仓库发布的jar包,新建一个maven项目,使用
mvn install:install-file -Dfile=src/lib/DependencyManager-1.0-SNAPSHOT.jar -DgroupId=com. meteor -DartifactId=dependency-manager -Dversion=1.0 -Dpackaging=jar
来导入到本地仓库,然后定义依赖
1 2 3 4 5
| <dependency> <groupId>com.meteor</groupId> <artifactId>dependency-manager</artifactId> <version>1.0</version> </dependency>
|
接下来,想想往常要干什么,比方说我有一个要发起网络请求的功能,想使用Httpclient库来操作。那么,引入依赖
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.2.3</version> </dependency>
<dependency> <groupId>org.apache.httpcomponents.core5</groupId> <artifactId>httpcore5-h2</artifactId> <version>5.2.4</version> </dependency>
|
接下来就是重头戏了,在plugin.yml
中定义依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| name: TestPlugin main: com.test.plugin.TestPluginMain version: 1.0 author: meteor api-version: 1.13
lib: httpcore5: url: 'https://repo.maven.apache.org/maven2/' groupId: 'org.apache.httpcomponents.core5' artifactId: 'httpcore5' version: '5.2.4' httpclient: url: 'https://repo.maven.apache.org/maven2/' groupId: 'org.apache.httpcomponents.client5' artifactId: 'httpclient5' version: '5.2.3'
|
在主类中,只需要这样
1 2 3 4 5
| @Override public void onEnable() {
DependencyManager.loadDependency(this); }
|
最后别忘了把DependcyManager打包到你的jar中,这是唯一需要内置的依赖。我使用maven-assembly-plugin
mvn clean package,在target中找到 xxx-jar-with-dependencies.jar,这就是打包的结果了!
运行,现在启动的时候如未存在依赖,会通过maven仓库下载到插件目录下的lib里并动态添加!
不过这种方式有没有其他隐患还待验证