前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jar包太多如何动态加载

jar包太多如何动态加载

作者头像
编程思维
发布2023-08-17 08:13:47
2470
发布2023-08-17 08:13:47
举报

jar文件太多怎么办

如果jar太多

项目就会变得臃肿

很多功能其实并不常有

只是偶尔调用时才需要

此时需要了解jar的按需调用

JVM 方式

使用JarInputStream调用

看代码

代码语言:javascript
复制
String url = "/home/mylib.jar";
String jarPath = "/home/runtime/test.jar";
JarInputStream jarInputStream = new JarInputStream(Files.newInputStream(Paths.get(url)));

Map<String, int[]> classByteMap = new HashMap<>();
byte[] buffer = new byte[1024 * 1024];
int head = 0;
int chunk = 256;
 
JarEntry jarEntry = jarInputStream.getNextJarEntry();
while (jarEntry != null) {
    String name = jarEntry.getName();
    if (name.endsWith(".class")) {
        String className = name.replaceAll("/", ".").replaceAll(".class", "");
        int size = 0, read;
        while (true) {
            read = jarInputStream.read(buffer, head + size, chunk);
            if (read == -1) {
                break;
            }
            size += read;
        }
        classByteMap.put(className, new int[]{head, size});
        head += size;
    }
    jarEntry = jarInputStream.getNextJarEntry();
}

这就是一个基本的例子

单独加载class

有时无需管理整个jar

而需要class

则可以使用classLoader

代码语言:javascript
复制
SecureClassLoader classLoader = new SecureClassLoader() {
    @Override
    protected Class<?> findClass(String name) {
        int[] arr = classByteMap.get(name);
        return super.defineClass(name, buffer, arr[0], arr[1]);
    }
};
 
Class<?> clazz = classLoader.loadClass("com.mi.Test");
Constructor<?> constructor = clazz.getConstructor();
Object demoEntry = constructor.newInstance();
Method entry = clazz.getDeclaredMethod("getId");
entry.invoke(demoEntry);

复杂应用

可以包装成工具类使用

代码语言:javascript
复制
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.cc.tx.util.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull;
 
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
 
 
public interface DematicClassManager {
 
    Logger log = LoggerFactory.getLogger(PluginClassManager.class);
 
    static URL parseJarURL (File jar) throws IOException {
        String jarFileUri = jar.toURI().toString() + "!/";
        return new URL("jar", "", -1, jarFileUri);
    }
    
    static List<URL> parseLibJars (@NonNull String lib) throws IOException {
        File libDir = new File(lib);
        File[] jars = libDir.listFiles((dir, name) -> name.endsWith(".jar") || name.endsWith(".zip"));
        List<URL> urls = Lists.newArrayList();
        if (jars != null) {
            for (int i = 0; i < jars.length; i++) {
                if (jars[i] != null && jars[i].isFile()) {
                    urls.add(parseJarURL(jars[i]));
                }
            }
        }
        return urls;
    }
    
    @SneakyThrows
    static void loadPluginLibJar (@NonNull String lib) throws IOException {
        URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
        addURL.setAccessible(true);
        parseLibJars(lib).forEach(e -> {
            try {
                addURL.invoke(classLoader, e);
                LogUtils.info(log, "loadPluginLibJar addURL {}", e.getPath());
            } catch (Exception e1) {
                throw new RuntimeException(e1);
            }
        });
    }
 
}

创建外部实现类

代码语言:javascript
复制
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
 
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
 
 
@Slf4j
public class DematicClassLoader extends URLClassLoader {
 
    private List<JarURLConnection> cachedResource = new CopyOnWriteArrayList<>();
 
    public DematicClassLoader() {
        super(new URL[] {}, ClassLoader.getSystemClassLoader());
    }
 
    public void loadLibJars (@NonNull String lib) throws IOException {
        PluginClassManager.parseLibJars(lib).forEach(e -> loadResource(e));
    }
 
    public void loadResource (@NonNull URL resource) {
        try {
            JarFile jar = null;
            log.info(resource.getPath());
            URLConnection uc = resource.openConnection();
            if (uc instanceof JarURLConnection) {
                uc.setUseCaches(true);
                ((JarURLConnection) uc).getManifest();
                cachedResource.add((JarURLConnection)uc);
                jar = ((JarURLConnection) uc).getJarFile();
            }
            addURL(resource);
            loadClassFromJar(jar);
        } catch (Exception e) {
           log.warn("Failed to cache plugin JAR file", resource.toExternalForm());
        }
    }
 
    private void loadClassFromJar(JarFile jar) {
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry jarEntry = entries.nextElement();
            String entryName = jarEntry.getName();
            if (entryName.charAt(0) == '/') {
                entryName = entryName.substring(1);
            }
            if (jarEntry.isDirectory() || !entryName.endsWith(".class")) {
                continue;
            }
            String className = entryName.substring(0, entryName.length() - 6);
            try {
                loadClass(className.replace("/", "."));
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
    }
 
    public void unloadResource() {
        for (JarURLConnection url : cachedResource) {
            try {
                url.getJarFile().close();
            } catch (Exception e) {
                log.warn("Failed to unload JAR file", e);
            }
        }
    }
 
}

这样就可以实现了

学习技术可以关注我

关注我私信可以获取打包学习资料

让我们一起进步成长

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • jar文件太多怎么办
  • JVM 方式
  • 单独加载class
  • 复杂应用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档