java自定义类加载器从网络位置加载字节码动态加入jvm以及整合springboot踩坑

java自定义类加载器从网络位置加载字节码动态加入jvm以及整合springboot踩坑,第1张

java自定义类加载器从网络位置加载字节码动态加入jvm以及整合springboot踩坑 springboot 打包之后无法动态加载问题解决

构建网络类加载器 继承ClassLoader 实现自定义类加载器

package com.net.utils;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;

public class NetClassLoder extends ClassLoader {

    private String url;

    public NetClassLoder(String url){
        this.url=url;

    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("类加载器回收了");
    }

    @Override
    public Class findClass(String className) throws ClassNotFoundException {
        System.out.println(className);
        Class aClass;
        byte[] classByNet = findClassByNet(className);
        System.out.println(classByNet);
        if(classByNet==null){
            System.out.println("没找到");
//            aClass = super.findClass(className);
//            System.out.println("找到这个"+aClass);
            return null;
        }
        aClass = defineClass(className,classByNet,0,classByNet.length);
        return aClass;
    }

    protected  byte[] findClassByNet(String className){
        // 从网络上读取的类的字节
        String path = pares2Url(className);
        try {
            URL url = new URL(path);
            InputStream ins = url.openStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int bufferSize = 4096;
            byte[] buffer = new byte[bufferSize];
            int bytesNumRead = 0;
            // 读取类文件的字节
            while ((bytesNumRead = ins.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesNumRead);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            return null;
        }

    }

    private String pares2Url(String className) {
        String replace = className.replace(".", "/");
        return url+"/"+replace+".class";
    }


}

//使用方式
   String domain="http://172.0.10.173";
            NetClassLoder classLoader = new NetClassLoder(domain);
            Class aClass = 			classLoader.findClass("com.load.plugin.impl.Command");
            Cmd cmd = (Cmd) aClass.newInstance();
            NetClass netClass = new NetClass();
            cmd.test();
以上存在的问题发现

当netclassloder类加载器 被构建的时候
每次类加载的时候都会调用finalclass 去寻找
由于是网络中只有我们的目的class文件,导致其他字节码找不到

问题解决

重写在netclassLoader中重写 loadclass 方法

  @Override
    public Class loadClass(String name) throws ClassNotFoundException {
    	//优先从网络找字节码
        Class loadClass =findClass(name);
       
        //第一情况 这个类 不需要由我们加载
        //第二种情况 这个类需要由我们加载 但是 确实加载不到
        if ( loadClass  ==null){
        //查看是否已经加载过 加载过就返回之前存在的
          loadClass = findLoadedClass(name); 
        }
           if(loadClass == null){
           //如果网络和之前都没加载过 就调用系统的类加载器去加载这个类
            loadClass=  getSystemClassLoader().loadClass(name);
             System.out.println(loadClass);
            }
        return loadClass;
    }
    //使用方式中修改为
       String domain="http://172.0.10.173";
            NetClassLoder classLoader = new NetClassLoder(domain);
            Class aClass = classLoader.loadClass("com.load.plugin.impl.Command");
            Cmd cmd = (Cmd) aClass.newInstance();
            NetClass netClass = new NetClass();
            cmd.test();

以上idea 调试 和整合springboot 直接使用都没问题 但是打包部署却有问题

spring boot 类加载的时候是通过 启动类加载器 加载springboot/lib 下的包
所以使用系统的类加载器是无法识别到maven 依赖的,尽管已经打包到里面了

问题解决思路 获取到springboot的启动类加载器 优先从springboot中加载jar

完整代码

package com.net.utils;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;

public class NetClassLoder extends ClassLoader {

    private String url;

    public NetClassLoder(String url){
        this.url=url;

    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("类加载器回收了");
    }

    @Override
    public Class findClass(String className) throws ClassNotFoundException {
        System.out.println(className);
        Class aClass;
        byte[] classByNet = findClassByNet(className);
        System.out.println(classByNet);
        if(classByNet==null){
            System.out.println("没找到");
//            aClass = super.findClass(className);
//            System.out.println("找到这个"+aClass);
            return null;
        }
        aClass = defineClass(className,classByNet,0,classByNet.length);
        return aClass;
    }

    protected  byte[] findClassByNet(String className){
        // 从网络上读取的类的字节
        String path = pares2Url(className);
        try {
            URL url = new URL(path);
            InputStream ins = url.openStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int bufferSize = 4096;
            byte[] buffer = new byte[bufferSize];
            int bytesNumRead = 0;
            // 读取类文件的字节
            while ((bytesNumRead = ins.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesNumRead);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            return null;
        }

    }

    @Override
    public Class loadClass(String name) throws ClassNotFoundException {
        Class loadClass = findClass(name);
        
        if ( loadClass ==null){
            loadClass = findLoadedClass(name);
        }
        if(loadClass==null){
            loadClass = Thread.currentThread().getContextClassLoader().loadClass(name);
            System.out.println(loadClass);
        }
        return loadClass;
    }


    private String pares2Url(String className) {
        String replace = className.replace(".", "/");
        return url+"/"+replace+".class";
    }


}


// 使用
  String domain="http://172.0.10.173";
            NetClassLoder classLoader = new NetClassLoder(domain);
            Class aClass = classLoader.loadClass("com.load.plugin.impl.Command");
            Cmd cmd = (Cmd) aClass.newInstance();
            NetClass netClass = new NetClass();
            cmd.test();

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5703567.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存