栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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();
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/705000.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号