美文网首页
SpringBoot热部署及自定义ClassLoader(部分热

SpringBoot热部署及自定义ClassLoader(部分热

作者: EnchantF | 来源:发表于2019-07-17 10:03 被阅读0次

SpringBoot热部署

  • 添加devtools依赖
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
    </dependency>
  • 修改相关配置


    步骤1
步骤2

注意事项:
代码修改后需要 离开idea 才会生效,例如:修改代码后,浏览器进行刷新,能看到程序在重新启动

java源码到JVM过程

类加载器ClassLoader

ClassLoader加载class文件到JVM步骤:
1.加载class文件
2.链接
3.初始化
4.使用
5.销毁

四个ClassLoader对象

  • BootStrapClassLoader启动类加载器 :负责加载JAVA核心类库
  • ExtClassLoader标准扩展类加载器:负责java.ext包
  • AppClassLoader系统类加载器:负责classpath下的类
  • CustomClassLoader:自定义类加载器
父子关系(不等于继承关系)

双亲委派机制
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载

委托机制的意义 — 防止内存中出现多份同样的字节码

defineClass:将class文件转换为JVM中的引用
loadClass:返回存在于JVM中的引用
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 判断JVM中是否存在该类的引用
            Class<?> c = findLoadedClass(name);
            // 如果没有,classLoader尝试加载该类
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    //  private final ClassLoader parent;
                   //判断是否存在父类加载器,父类加载器进行加载(递归)
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        // BootStrapClassLoader进行加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

因此,要实现热部署,必须打破双亲委派(因为同一个类只存在一份该类的字节码),自己定义类加载器

自定义类加载器

public Class<?> loadClass(String name) throws ClassNotFoundException {

        // TODO 加锁
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            // 不需要我们加载
            if (!clazz.contains(name)) {
                c = getSystemClassLoader().loadClass(name);
            } else {
                throw new ClassNotFoundException("找不到该class");
            }
        }

        return c;
    }
 private void loadClassPath(File file) throws IOException {
        if (file.isDirectory()) {
            for (File file1 : file.listFiles()) {
                loadClassPath(file1);
            }
        } else {

            String fileName = file.getName();
            String filePath = file.getPath();
            String endName = fileName.substring(fileName.lastIndexOf(".") + 1);
            if ("class".equals(endName)) {
                InputStream inputStream = new FileInputStream(file);
                byte[] data = new byte[(int) file.length()];
                inputStream.read(data);

                String className = filePathToClassName(filePath);
                clazz.add(className);
                defineClass(className, data, 0, data.length);

            }
        }
    }

完整代码路径

相关文章

网友评论

      本文标题:SpringBoot热部署及自定义ClassLoader(部分热

      本文链接:https://www.haomeiwen.com/subject/ripflctx.html