Silentdoer

导航

通过类加载机制实现加载相同包名和类名的不同版本的类

有些地方有这种需求,要同时用到两个不兼容的jar包版本的某个工具类,它们的包名和类名又是一样的,即比如都叫org.xxx.Foo;

在项目里已经用到了该jar包的1.0版本,但是现在新的需求要用该jar包的2.0版本,但是2.0版本的jar包的工具类也是叫org.xxx.Foo;

这就导致了需要同时加载这两个签名一样的类(无法改造为一个jar,领导不允许)

可以用URLClassLoader实现:

package org;

import java.io.File;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class Main {

    public static void main(String[] args) throws Exception {
        File jar1 = new File("E:\\Projects\\bcprovextjdk15on_unionpay\\out\\artifacts\\jar1.jar");
        File jar2 = new File("E:\\Projects\\bcprovextjdk15on_unionpay\\out\\artifacts\\jar2.jar");
        JarURLClassLoader loader1 = new JarURLClassLoader(jar1.toURI().toURL());
        JarURLClassLoader loader2 = new JarURLClassLoader(jar2.toURI().toURL());

        Class<?> clazzTest1 = loader1.loadClass("me.silentdoer.Test");
        Class<?> clazzTest2 = loader2.loadClass("me.silentdoer.Test");

        Object o1 = clazzTest1.newInstance();
        System.err.println(o1.getClass());
        Method prints1 = clazzTest1.getMethod("prints");
        prints1.invoke(o1);

        Object o2 = clazzTest2.newInstance();
        System.err.println(o2.getClass());
        Method prints2 = clazzTest2.getMethod("prints");
        prints2.invoke(o2);
    }

    public static class JarURLClassLoader {
        private URL jar;
        private URLClassLoader classLoader;

        public JarURLClassLoader(URL jar) {
            this.jar = jar;
            classLoader = new URLClassLoader(new URL[]{jar});
        }

        /**
         * 加载类,如:me.silentdoer.AClass
         *
         * @param name
         * @return
         */
        private Class<?> loadClass(String name) {
            try {
                return classLoader.loadClass(name);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }

        /**
         * 在指定包路径下加载子类
         *
         * @param superClass
         * @param basePackage
         * @return
         */
        public Set<Class> loadClass(Class<?> superClass, String basePackage) {
            JarFile jarFile;
            try {
                // 将jar文件的URL转换为JarFile对象
                jarFile = ((JarURLConnection) jar.openConnection()).getJarFile();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            return loadClassFromJar(superClass, basePackage, jarFile);
        }

        private Set<Class> loadClassFromJar(Class<?> superClass, String basePackage, JarFile jar) {
            Set<Class> classes = new HashSet<>();
            String pkgPath = basePackage.replace(".", "/");
            Enumeration<JarEntry> entries = jar.entries();
            Class<?> clazz;
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                String entryName = jarEntry.getName();
                if (entryName.charAt(0) == '/') {
                    entryName = entryName.substring(1);
                }
                if (jarEntry.isDirectory() || !entryName.startsWith(pkgPath) || !entryName.endsWith(".class")) {
                    continue;
                }
                String className = entryName.substring(0, entryName.length() - 6);
                clazz = loadClass(className.replace("/", "."));
                if (clazz != null && !clazz.isInterface() && superClass.isAssignableFrom(clazz)) {
                    classes.add(clazz);
                }
            }
            return classes;
        }
    }
}

 

posted on 2022-11-28 23:08  Silentdoer  阅读(218)  评论(0编辑  收藏  举报