Làm cách nào để tải các tệp JAR động tại Runtime?


308

Tại sao nó rất khó để làm điều này trong Java? Nếu bạn muốn có bất kỳ loại hệ thống mô-đun nào, bạn cần có thể tải các tệp JAR một cách linh hoạt. Tôi đã nói có một cách để làm điều đó bằng cách viết của riêng bạn ClassLoader, nhưng đó là rất nhiều công việc cho một cái gì đó (ít nhất là trong suy nghĩ của tôi) cũng dễ như gọi một phương thức với tệp JAR làm đối số của nó.

Bất kỳ đề xuất cho mã đơn giản mà làm điều này?


4
Tôi muốn làm như vậy nhưng chạy jar đã tải trong một môi trường nhiều hộp cát hơn (vì lý do bảo mật rõ ràng). Ví dụ, tôi muốn chặn tất cả các truy cập mạng và hệ thống tập tin.
Jus12

Câu trả lời:


253

Lý do khó đó là bảo mật. Trình nạp lớp có nghĩa là bất biến; bạn không nên thêm các lớp vào nó khi chạy. Tôi thực sự rất ngạc nhiên khi làm việc với trình nạp lớp hệ thống. Đây là cách bạn làm nó để tạo trình nạp lớp con của riêng bạn:

URLClassLoader child = new URLClassLoader(
        new URL[] {myJar.toURI().toURL()},
        this.getClass().getClassLoader()
);
Class classToLoad = Class.forName("com.MyClass", true, child);
Method method = classToLoad.getDeclaredMethod("myMethod");
Object instance = classToLoad.newInstance();
Object result = method.invoke(instance);

Đau đớn, nhưng nó có.


16
Chỉ có vấn đề với cách tiếp cận này là bạn cần biết các lớp trong lọ là gì. Trái ngược với việc chỉ tải một thư mục các lọ và sau đó khởi tạo các lớp. Tôi đang hiểu lầm nó?
Allain Lalonde

10
Phương thức này hoạt động rất tốt khi chạy trong IDE của tôi, nhưng khi tôi xây dựng JAR của mình, tôi nhận được ClassNotFoundException khi gọi Class.forName ().
darrickc

29
Sử dụng phương pháp này, bạn cần đảm bảo rằng bạn sẽ không gọi phương thức tải này nhiều lần cho mỗi lớp. Vì bạn đang tạo một trình nạp lớp mới cho mọi hoạt động tải, nên không thể biết liệu lớp đã được tải trước đó chưa. Điều này có thể có hậu quả xấu. Ví dụ, singletons không hoạt động vì lớp được tải nhiều lần và do đó các trường tĩnh tồn tại nhiều lần.
Eduard Wirch

8
Làm. Ngay cả với sự phụ thuộc vào các lớp khác trong bình. Dòng đầu tiên không đầy đủ. Tôi đã sử dụng URLClassLoader child = new URLClassLoader (new URL[] {new URL("file://./my.jar")}, Main.class.getClassLoader());giả sử rằng tệp jar được gọi my.jarvà nằm trong cùng thư mục.
hàm

4
Đừng quên URL url = file.toURI (). ToURL ();
johnstosh

139

Giải pháp sau đây là hackish, vì nó sử dụng sự phản chiếu để bỏ qua việc đóng gói, nhưng nó hoạt động hoàn hảo:

File file = ...
URL url = file.toURI().toURL();

URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, url);

40
Tất cả các hoạt động trên phản hồi này làm cho tôi tự hỏi có bao nhiêu hack chúng tôi đang chạy trong sản xuất trong các hệ thống khác nhau. Tôi không chắc là tôi muốn biết câu trả lời
Andrei Savu

6
Sẽ không hoạt động tốt nếu trình tải lớp hệ thống xảy ra không phải là thứ gì đó ngoài URLClassLoader ...
Gus

6
Java 9+ cảnh báo rằng URLClassLoader.class.getDeclaredMethod("addURL", URL.class)việc sử dụng phản ánh bất hợp pháp và sẽ thất bại trong tương lai.
Charlweed

1
Bất kỳ ý tưởng làm thế nào để cập nhật mã này để làm việc với Java 9+?
FiReTiTi

1
@FiReTiTi Vâng !!
Mordechai

51

Bạn nên xem OSGi , ví dụ được triển khai trong Nền tảng Eclipse . Nó làm chính xác điều đó. Bạn có thể cài đặt, gỡ cài đặt, bắt đầu và dừng các gói được gọi là các tệp JAR hiệu quả. Nhưng nó làm được nhiều hơn một chút, vì nó cung cấp các dịch vụ ví dụ có thể được phát hiện động trong các tệp JAR khi chạy.

Hoặc xem đặc tả cho Hệ thống Mô-đun Java .


41

Làm thế nào về khung trình nạp lớp JCL ? Tôi phải thừa nhận, tôi đã không sử dụng nó, nhưng nó có vẻ đầy hứa hẹn.

Ví dụ sử dụng:

JarClassLoader jcl = new JarClassLoader();
jcl.add("myjar.jar"); // Load jar file  
jcl.add(new URL("http://myserver.com/myjar.jar")); // Load jar from a URL
jcl.add(new FileInputStream("myotherjar.jar")); // Load jar file from stream
jcl.add("myclassfolder/"); // Load class folder  
jcl.add("myjarlib/"); // Recursively load all jar files in the folder/sub-folder(s)

JclObjectFactory factory = JclObjectFactory.getInstance();
// Create object of loaded class  
Object obj = factory.create(jcl, "mypackage.MyClass");

9
Nó cũng có lỗi và thiếu một số triển khai quan trọng, ví dụ như findResource (...). Hãy sẵn sàng dành những đêm tuyệt vời để điều tra lý do tại sao một số thứ nhất định không hoạt động =)
Sergey Karpushin

Tôi vẫn đang tự hỏi @ tuyên bố của Sergekarpushin vẫn còn vì dự án đã được cập nhật theo thời gian lên phiên bản chính thứ hai. Muốn nghe kinh nghiệm.
Erdin Eray

2
@ErdinEray, đó là một câu hỏi rất hay mà tôi cũng tự hỏi mình vì chúng tôi đã "buộc" phải chuyển sang OpenJDK. Tôi vẫn làm việc trên các dự án java và tôi không có bất kỳ bằng chứng nào cho thấy Open JDK sẽ làm bạn thất vọng trong những ngày này (mặc dù sau đó tôi đã gặp vấn đề). Tôi đoán tôi rút lại yêu cầu của mình cho đến khi tôi va vào một thứ khác.
Sergey Karpushin

20

Đây là một phiên bản không được tán thành. Tôi đã sửa đổi bản gốc để loại bỏ các chức năng không dùng nữa.

/**************************************************************************************************
 * Copyright (c) 2004, Federal University of So Carlos                                           *
 *                                                                                                *
 * All rights reserved.                                                                           *
 *                                                                                                *
 * Redistribution and use in source and binary forms, with or without modification, are permitted *
 * provided that the following conditions are met:                                                *
 *                                                                                                *
 *     * Redistributions of source code must retain the above copyright notice, this list of      *
 *       conditions and the following disclaimer.                                                 *
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of   *
 *     * conditions and the following disclaimer in the documentation and/or other materials      *
 *     * provided with the distribution.                                                          *
 *     * Neither the name of the Federal University of So Carlos nor the names of its            *
 *     * contributors may be used to endorse or promote products derived from this software       *
 *     * without specific prior written permission.                                               *
 *                                                                                                *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS                            *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT                              *
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR                          *
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR                  *
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,                          *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,                            *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR                             *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF                         *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING                           *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS                             *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                   *
 **************************************************************************************************/
/*
 * Created on Oct 6, 2004
 */
package tools;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * Useful class for dynamically changing the classpath, adding classes during runtime. 
 */
public class ClasspathHacker {
    /**
     * Parameters of the method to add an URL to the System classes. 
     */
    private static final Class<?>[] parameters = new Class[]{URL.class};

    /**
     * Adds a file to the classpath.
     * @param s a String pointing to the file
     * @throws IOException
     */
    public static void addFile(String s) throws IOException {
        File f = new File(s);
        addFile(f);
    }

    /**
     * Adds a file to the classpath
     * @param f the file to be added
     * @throws IOException
     */
    public static void addFile(File f) throws IOException {
        addURL(f.toURI().toURL());
    }

    /**
     * Adds the content pointed by the URL to the classpath.
     * @param u the URL pointing to the content to be added
     * @throws IOException
     */
    public static void addURL(URL u) throws IOException {
        URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
        Class<?> sysclass = URLClassLoader.class;
        try {
            Method method = sysclass.getDeclaredMethod("addURL",parameters);
            method.setAccessible(true);
            method.invoke(sysloader,new Object[]{ u }); 
        } catch (Throwable t) {
            t.printStackTrace();
            throw new IOException("Error, could not add URL to system classloader");
        }        
    }

    public static void main(String args[]) throws IOException, SecurityException, ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
        addFile("C:\\dynamicloading.jar");
        Constructor<?> cs = ClassLoader.getSystemClassLoader().loadClass("test.DymamicLoadingTest").getConstructor(String.class);
        DymamicLoadingTest instance = (DymamicLoadingTest)cs.newInstance();
        instance.test();
    }
}

19
Tôi ghét phải làm hỏng một chủ đề cũ, nhưng tôi muốn chỉ ra rằng tất cả nội dung trên stackoverflow đều được cấp phép CC. Tuyên bố bản quyền của bạn là không hiệu quả. stackoverflow.com/faq#editing
Huckle

43
Ừm. Về mặt kỹ thuật, nội dung gốc được CC cấp phép, nhưng nếu bạn đăng nội dung có bản quyền ở đây, điều đó sẽ không loại bỏ sự thật rằng nội dung đó có bản quyền. Nếu tôi đăng một bức ảnh về chuột Mickey, nó sẽ không được cấp phép CC. Vì vậy, tôi đang thêm tuyên bố bản quyền trở lại.
Jason S

19

Mặc dù hầu hết các giải pháp được liệt kê ở đây là hack (trước JDK 9) khó cấu hình (tác nhân) hoặc không hoạt động nữa (bài JDK 9) tôi thấy thực sự sốc khi không ai đề cập đến một phương pháp được ghi chép rõ ràng .

Bạn có thể tạo một trình nạp lớp hệ thống tùy chỉnh và sau đó bạn có thể tự do làm bất cứ điều gì bạn muốn. Không cần phản ánh và tất cả các lớp chia sẻ cùng một trình nạp lớp.

Khi bắt đầu JVM, thêm cờ này:

java -Djava.system.class.loader=com.example.MyCustomClassLoader

Trình nạp lớp phải có một hàm tạo chấp nhận trình nạp lớp, phải được đặt làm mẹ của nó. Hàm tạo sẽ được gọi khi khởi động JVM và trình nạp lớp hệ thống thực sẽ được thông qua, lớp chính sẽ được tải bởi trình nạp tùy chỉnh.

Để thêm bình, chỉ cần gọi ClassLoader.getSystemClassLoader()và bỏ nó vào lớp của bạn.

Kiểm tra việc thực hiện này cho một trình nạp lớp được chế tạo cẩn thận. Xin lưu ý, bạn có thể thay đổi add()phương thức thành công khai.


Cảm ơn bạn - điều này thực sự hữu ích! Tất cả các tài liệu tham khảo khác về các phương thức sử dụng web cho JDK 8 trở về trước - có nhiều vấn đề.
Vishal Biyani

15

Với Java 9 , các câu trả lời URLClassLoaderbây giờ đưa ra một lỗi như:

java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader

Điều này là do các trình nạp lớp được sử dụng đã thay đổi. Thay vào đó, để thêm vào trình tải lớp hệ thống, bạn có thể sử dụng API thiết bị thông qua một tác nhân.

Tạo một lớp đại lý:

package ClassPathAgent;

import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;

public class ClassPathAgent {
    public static void agentmain(String args, Instrumentation instrumentation) throws IOException {
        instrumentation.appendToSystemClassLoaderSearch(new JarFile(args));
    }
}

Thêm META-INF / MANIFEST.MF và đặt nó vào tệp JAR với lớp tác nhân:

Manifest-Version: 1.0
Agent-Class: ClassPathAgent.ClassPathAgent

Chạy đại lý:

Điều này sử dụng thư viện tác nhân byte để thêm tác nhân vào JVM đang chạy:

import java.io.File;

import net.bytebuddy.agent.ByteBuddyAgent;

public class ClassPathUtil {
    private static File AGENT_JAR = new File("/path/to/agent.jar");

    public static void addJarToClassPath(File jarFile) {
        ByteBuddyAgent.attach(AGENT_JAR, String.valueOf(ProcessHandle.current().pid()), jarFile.getPath());
    }
}

9

Thứ tốt nhất tôi tìm thấy là org.apache.xbean . Classloader.JarFileClassLoader, một phần của dự án XBean .

Đây là một phương pháp ngắn mà tôi đã sử dụng trước đây, để tạo trình tải lớp từ tất cả các tệp lib trong một thư mục cụ thể

public void initialize(String libDir) throws Exception {
    File dependencyDirectory = new File(libDir);
    File[] files = dependencyDirectory.listFiles();
    ArrayList<URL> urls = new ArrayList<URL>();
    for (int i = 0; i < files.length; i++) {
        if (files[i].getName().endsWith(".jar")) {
        urls.add(files[i].toURL());
        //urls.add(files[i].toURI().toURL());
        }
    }
    classLoader = new JarFileClassLoader("Scheduler CL" + System.currentTimeMillis(), 
        urls.toArray(new URL[urls.size()]), 
        GFClassLoader.class.getClassLoader());
}

Sau đó, để sử dụng trình nạp lớp, chỉ cần làm:

classLoader.loadClass(name);

Lưu ý rằng dự án dường như không được duy trì tốt. Lộ trình của họ cho tương lai chứa một số bản phát hành cho năm 2014, ví dụ.
Zero3

6

Nếu bạn đang làm việc trên Android, đoạn mã sau sẽ hoạt động:

String jarFile = "path/to/jarfile.jar";
DexClassLoader classLoader = new DexClassLoader(jarFile, "/data/data/" + context.getPackageName() + "/", null, getClass().getClassLoader());
Class<?> myClass = classLoader.loadClass("MyClass");

6

Đây là một cách giải quyết nhanh cho phương thức của Allain để làm cho nó tương thích với các phiên bản Java mới hơn:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try {
    Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class);
    method.setAccessible(true);
    method.invoke(classLoader, new File(jarPath).toURI().toURL());
} catch (NoSuchMethodException e) {
    Method method = classLoader.getClass()
            .getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
    method.setAccessible(true);
    method.invoke(classLoader, jarPath);
}

Lưu ý rằng nó dựa vào kiến ​​thức về triển khai nội bộ của JVM cụ thể, vì vậy nó không lý tưởng và nó không phải là một giải pháp phổ quát. Nhưng đó là một cách giải quyết nhanh chóng và dễ dàng nếu bạn biết rằng bạn sẽ sử dụng OpenJDK hoặc Oracle JVM tiêu chuẩn. Nó cũng có thể bị hỏng vào một thời điểm nào đó trong tương lai khi phiên bản JVM mới được phát hành, vì vậy bạn cần ghi nhớ điều đó.


Với Java 11.0.2, tôi nhận được:Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make void jdk.internal.loader.ClassLoaders$AppClassLoader.appendToClassPathForInstrumentation(java.lang.String) accessible: module java.base does not "opens jdk.internal.loader" to unnamed module @18ef96
Richard Żak

Hoạt động với Java 8 EE trong môi trường máy chủ ứng dụng.
Ngày

4

Giải pháp được đề xuất bởi jodonnell là tốt nhưng nên được tăng cường một chút. Tôi đã sử dụng bài đăng này để phát triển ứng dụng của mình thành công.

Chỉ định chủ đề hiện tại

Đầu tiên chúng ta phải thêm

Thread.currentThread().setContextClassLoader(classLoader);

hoặc bạn sẽ không thể tải tài nguyên (chẳng hạn như spring / bối cảnh) được lưu trữ vào tệp jar.

Không bao gồm

bình của bạn vào trình nạp lớp cha hoặc bạn sẽ không thể hiểu ai đang tải cái gì.

xem thêm Sự cố tải lại một jar bằng URLClassLoader

Tuy nhiên, khung OSGi vẫn là cách tốt nhất.


2
Câu trả lời của bạn có vẻ hơi khó hiểu, và có lẽ phù hợp hơn như là một nhận xét cho câu trả lời của jodonnell nếu đó chỉ là một cải tiến đơn giản.
Zero3

4

Một phiên bản khác của giải pháp hackish từ Allain, cũng hoạt động trên JDK 11:

File file = ...
URL url = file.toURI().toURL();
URLClassLoader sysLoader = new URLClassLoader(new URL[0]);

Method sysMethod = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
sysMethod.setAccessible(true);
sysMethod.invoke(sysLoader, new Object[]{url});

Trên JDK 11, nó đưa ra một số cảnh báo không dùng nữa nhưng đóng vai trò là giải pháp tạm thời cho những người sử dụng giải pháp Allain trên JDK 11.


Tôi cũng có thể loại bỏ bình?
dùng7294900

3

Một giải pháp làm việc khác sử dụng Thiết bị đo đạc phù hợp với tôi. Nó có lợi thế là sửa đổi tìm kiếm trình nạp lớp, tránh các vấn đề về khả năng hiển thị của lớp đối với các lớp phụ thuộc:

Tạo một lớp đại lý

Trong ví dụ này, nó phải nằm trên cùng một jar được gọi bởi dòng lệnh:

package agent;

import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;

public class Agent {
   public static Instrumentation instrumentation;

   public static void premain(String args, Instrumentation instrumentation) {
      Agent.instrumentation = instrumentation;
   }

   public static void agentmain(String args, Instrumentation instrumentation) {
      Agent.instrumentation = instrumentation;
   }

   public static void appendJarFile(JarFile file) throws IOException {
      if (instrumentation != null) {
         instrumentation.appendToSystemClassLoaderSearch(file);
      }
   }
}

Sửa đổi MANIFEST.MF

Thêm tài liệu tham khảo cho các đại lý:

Launcher-Agent-Class: agent.Agent
Agent-Class: agent.Agent
Premain-Class: agent.Agent

Tôi thực sự sử dụng Netbeans, vì vậy bài đăng này giúp về cách thay đổi manifest.mf

Đang chạy

Cái Launcher-Agent-Classnày chỉ được hỗ trợ trên JDK 9+ và chịu trách nhiệm tải tác nhân mà không xác định rõ ràng nó trên dòng lệnh:

 java -jar <your jar>

Cách hoạt động trên JDK 6+ là xác định -javaagentđối số:

java -javaagent:<your jar> -jar <your jar>

Thêm Jar mới trong thời gian chạy

Sau đó, bạn có thể thêm jar khi cần thiết bằng cách sử dụng lệnh sau:

Agent.appendJarFile(new JarFile(<your file>));

Tôi không tìm thấy bất kỳ vấn đề sử dụng này trên tài liệu.


Vì một số lý do khi sử dụng giải pháp này, tôi nhận được "Ngoại lệ trong luồng" chính "java.lang.ClassNotFoundException: agent.Agent". Tôi đã đóng gói lớp "Đại lý" vào ứng dụng "chiến tranh" chính của mình, vì vậy tôi chắc chắn nó ở đó
Sergei Ledvanov

3

Trong trường hợp bất kỳ ai tìm kiếm điều này trong tương lai, cách này hoạt động với tôi với OpenJDK 13.0.2.

Tôi có nhiều lớp mà tôi cần khởi tạo động khi chạy, mỗi lớp có một đường dẫn khác nhau.

Trong mã này, tôi đã có một đối tượng được gọi là pack, chứa một số siêu dữ liệu về lớp tôi đang cố tải. Phương thức getObjectFile () trả về vị trí của tệp lớp cho lớp. Phương thức getObjectRootPath () trả về đường dẫn đến thư mục bin / chứa các tệp lớp bao gồm lớp mà tôi đang cố gắng khởi tạo. Phương thức getLibPath () trả về đường dẫn đến một thư mục chứa các tệp jar cấu thành đường dẫn lớp cho mô-đun mà lớp là một phần của.

File object = new File(pack.getObjectFile()).getAbsoluteFile();
Object packObject;
try {
    URLClassLoader classloader;

    List<URL> classpath = new ArrayList<>();
    classpath.add(new File(pack.getObjectRootPath()).toURI().toURL());
    for (File jar : FileUtils.listFiles(new File(pack.getLibPath()), new String[] {"jar"}, true)) {
        classpath.add(jar.toURI().toURL());
    }
    classloader = new URLClassLoader(classpath.toArray(new URL[] {}));

    Class<?> clazz = classloader.loadClass(object.getName());
    packObject = clazz.getDeclaredConstructor().newInstance();

} catch (Exception e) {
    e.printStackTrace();
    throw e;
}
return packObject;

Tôi đã sử dụng phụ thuộc Maven: org.xeustechnology: jcl-core: 2.8 để làm điều này trước đây, nhưng sau khi di chuyển qua JDK 1.8, đôi khi nó bị đóng băng và không bao giờ quay lại bị kẹt "chờ tham chiếu" tại Reference :: WaitForReferencePendingList ().

Tôi cũng đang giữ một bản đồ của các trình nạp lớp để chúng có thể được sử dụng lại nếu lớp tôi đang cố gắng khởi tạo nằm trong cùng một mô-đun như một lớp mà tôi đã khởi tạo, tôi muốn giới thiệu.


2

vui lòng xem dự án này mà tôi đã bắt đầu: proxy-object lib

Lib này sẽ tải jar từ hệ thống tập tin hoặc bất kỳ vị trí nào khác. Nó sẽ dành một trình nạp lớp cho jar để đảm bảo không có xung đột thư viện. Người dùng sẽ có thể tạo bất kỳ đối tượng nào từ jar đã tải và gọi bất kỳ phương thức nào trên đó. Lib này được thiết kế để tải các tệp được biên dịch trong Java 8 từ cơ sở mã hỗ trợ Java 7.

Để tạo một đối tượng:

    File libDir = new File("path/to/jar");

    ProxyCallerInterface caller = ObjectBuilder.builder()
            .setClassName("net.proxy.lib.test.LibClass")
            .setArtifact(DirArtifact.builder()
                    .withClazz(ObjectBuilderTest.class)
                    .withVersionInfo(newVersionInfo(libDir))
                    .build())
            .build();
    String version = caller.call("getLibVersion").asString();

ObjectBuilder hỗ trợ các phương thức xuất xưởng, gọi các hàm tĩnh và gọi lại các cài đặt giao diện. tôi sẽ đăng thêm ví dụ trên trang readme.


2

Đây có thể là phản hồi muộn, tôi có thể thực hiện điều này (một ví dụ đơn giản cho fastutil-8.2.2.jar) bằng cách sử dụng lớp jhplot.Web từ DataMelt ( http://jwork.org/dmelt )

import jhplot.Web;
Web.load("http://central.maven.org/maven2/it/unimi/dsi/fastutil/8.2.2/fastutil-8.2.2.jar"); // now you can start using this library

Theo tài liệu, tệp này sẽ được tải xuống bên trong "lib / user" và sau đó được tải động, vì vậy bạn có thể bắt đầu ngay lập tức bằng cách sử dụng các lớp từ tệp jar này trong cùng một chương trình.


1

Tôi cần tải một tệp jar khi chạy cho cả java 8 và java 9+ (các nhận xét trên không hoạt động cho cả hai phiên bản này). Đây là phương pháp để làm điều đó (sử dụng Spring Boot 1.5.2 nếu nó có thể liên quan).

public static synchronized void loadLibrary(java.io.File jar) {
    try {            
        java.net.URL url = jar.toURI().toURL();
        java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
        method.setAccessible(true); /*promote the method to public access*/
        method.invoke(Thread.currentThread().getContextClassLoader(), new Object[]{url});
    } catch (Exception ex) {
        throw new RuntimeException("Cannot load library from jar file '" + jar.getAbsolutePath() + "'. Reason: " + ex.getMessage());
    }
}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.