Java 双亲委派问题&解决实战(二)

接上一篇: Java 双亲委派问题&解决实战(一),讨论依赖中的类加载问题

设想如下场景

  • demo1 的1.0;2.0;3.0 三个版本分别被其它模块依赖;如果业务bundle-main要正常运行依赖结果,这显然要冲突
    在这里插入图片描述
    项目工程如下:
    在这里插入图片描述
    经过上一篇文章,显然只要我们自定义类加载器,每个模块类正确加载对应版本的即可,代码如下
package com.dq.bundle.main;

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

/**
 * @Author mubi
 * @Date 2021/3/13 10:47
 */
public class Main {
    public static void main(String[] args) throws
            MalformedURLException,
            ClassNotFoundException,
            IllegalAccessException,
            InstantiationException,
            NoSuchMethodException,
            InvocationTargetException {
        Main m = new Main();
        String hello1Path = "/Users/mubi/IdeaProjects/bundle/demo2/src/main/lib/demo1-1.0-SNAPSHOT.jar";
        String hello2Path = "/Users/mubi/IdeaProjects/bundle/demo3/src/main/lib/demo1-2.0-SNAPSHOT.jar";
        String hello3Path = "/Users/mubi/IdeaProjects/bundle/demo1/target/demo1-3.0-SNAPSHOT.jar";
        URLClassLoader helloClassLoader1 = new URLClassLoader(m.convert2URLArray(hello1Path));
        URLClassLoader helloClassLoader2 = new URLClassLoader(m.convert2URLArray(hello2Path));
        URLClassLoader helloClassLoader3 = new URLClassLoader(m.convert2URLArray(hello3Path));


        /**
         * 正常加载Hello类 版本3
         */
        Class<?> helloClass3 = helloClassLoader3.loadClass("com.dq.bundle.demo1.Hello");
        Object helloInstance = helloClass3.newInstance();
        Method sayMethod = helloClass3.getMethod("say", String.class);
        sayMethod.invoke(helloInstance, "world");

        // User类使用 Hello 版本1
        String userPath = "/Users/mubi/IdeaProjects/bundle/demo2/target/demo2-3.0-SNAPSHOT.jar";
        SelfClassLoader userLoader = new SelfClassLoader(m.convert2URLArray(userPath),
                helloClassLoader1);

        // Teacher类使用 Hello 版本2
        String teacherPath = "/Users/mubi/IdeaProjects/bundle/demo3/target/demo3-3.0-SNAPSHOT.jar";
        SelfClassLoader teacherLoader = new SelfClassLoader(m.convert2URLArray(teacherPath),
                helloClassLoader2);


        /**
         *  正常加载User类, 并使用传递过来的 helloClassLoader1 正常加载Hello类
         */
        Class<?> helloClass1 = helloClassLoader1.loadClass("com.dq.bundle.demo1.Hello");
        Object helloInstance1 = helloClass1.newInstance();
        Class<?> userClass = userLoader.loadClass("com.dq.bundle.demo2.User");
        Object userInstance = userClass.newInstance();
        Method welcomeMethod = userClass.getMethod("welcome", helloClass1);
        welcomeMethod.invoke(userInstance, helloInstance1);

        /**
         * 正常加载Teacher类,并使用传递过来的 helloClassLoader2 正常加载Hello类
         */
        Class<?> helloClass2 = helloClassLoader2.loadClass("com.dq.bundle.demo1.Hello");
        Object helloInstance2 = helloClass2.newInstance();
        Class<?> teacherClass = teacherLoader.loadClass("com.dq.bundle.demo3.Teacher");
        Object teacherInstance = teacherClass.newInstance();
        Method welcomeTeacherMethod = teacherClass.getMethod("welcome", helloClass2);
        welcomeTeacherMethod.invoke(teacherInstance, helloInstance2);
    }

    /**
     * 自定义类加载器,可以传入其它类加载器
     */
    static class SelfClassLoader extends URLClassLoader {
        private ClassLoader parentClassLoader;

        public SelfClassLoader(URL[] urls, ClassLoader classLoader) {
            super(urls);
            this.parentClassLoader = classLoader;
        }

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            Class<?> clazz = loadFromParent(name);
            if (clazz != null) {
                return clazz;
            }
            return super.loadClass(name);
        }

        public Class<?> loadFromParent(String name) {
            // 从当前classLoader加载
            Class<?> loadClass = super.findLoadedClass(name);

            try {
                if (loadClass == null) {
                    // 用父加载加载,这里是自己传入的类加载器
                    loadClass = this.parentClassLoader.loadClass(name);
                }
            } catch (ClassNotFoundException e) {
//                e.printStackTrace();
            }
            return loadClass;
        }
    }

    private URL[] convert2URLArray(String filePath) throws MalformedURLException {
        File f = new File(filePath);
        URL[] urls = new URL[1];
        urls[0] = f.toURI().toURL();
        return urls;
    }
}

正常运行如下
在这里插入图片描述
附:多版本类加载问题


如上可以正常运行3个demo1版本,本质原因:类加载器 + 类全限定名 才是确定一个类的;我们都是com.dq.bundle.demo1.Hello这个类限定名,但是我们有3个不同的类加载器,这就让我们能够在一个工程中同时使用3个版本的demo1

String hello1Path = "/Users/mubi/IdeaProjects/bundle/demo2/src/main/lib/demo1-1.0-SNAPSHOT.jar";
String hello2Path = "/Users/mubi/IdeaProjects/bundle/demo3/src/main/lib/demo1-2.0-SNAPSHOT.jar";
String hello3Path = "/Users/mubi/IdeaProjects/bundle/demo1/target/demo1-3.0-SNAPSHOT.jar";
URLClassLoader helloClassLoader1 = new URLClassLoader(m.convert2URLArray(hello1Path));
URLClassLoader helloClassLoader2 = new URLClassLoader(m.convert2URLArray(hello2Path));
URLClassLoader helloClassLoader3 = new URLClassLoader(m.convert2URLArray(hello3Path));

而所谓的类加载则是自己重写了loadClass方法实现的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值