zoukankan      html  css  js  c++  java
  • 类加载器学习

    ClassLoader

      一切的Java类都必须经过JVM加载后才能运行,而ClassLoader的主要作用就是Java类文件的加载。在JVM类加载器中最顶层的是Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)、App ClassLoader(系统类加载器),AppClassLoader是默认的类加载器,如果类加载时我们不指定类加载器的情况下,默认会使用AppClassLoader加载类,ClassLoader.getSystemClassLoader()返回的系统类加载器也是AppClassLoader。

      值得注意的是某些时候我们获取一个类的类加载器时候可能会返回一个null值,如:java.io.File.class.getClassLoader()将返回一个null对象,因为java.io.File类在JVM初始化的时候会被Bootstrap ClassLoader(引导类加载器)加载(该类加载器实现于JVM层,采用C++编写),我们在尝试获取被Bootstrap ClassLoader类加载器所加载的类的ClassLoader时候都会返回null。

      ClassLoader类有如下核心方法:

      1. loadClass(加载指定的Java类)

      2. findClass(查找指定的Java类)

      3. findLoadedClass(查找JVM已经加载过的类)

      4. defineClass(定义一个Java类)

      5. resolveClass(链接指定的Java类)

      Java类动态加载方式

      Java类加载方式分为显式和隐式,显式即我们通常使用Java反射或者ClassLoader来动态加载一个类对象,而隐式指的是类名.方法名()或new类实例。显式类加载方式也可以理解为类动态加载,我们可以自定义类加载器去加载任意的类。

      常用的类动态加载方式:

      // 反射加载TestHelloWorld示例 Class.forName("com.anbai.sec.classloader.TestHelloWorld"); // ClassLoader加载TestHelloWorld示例 this.getClass().getClassLoader().loadClass("com.anbai.sec.classloader.TestHelloWorld");

      Class.forName("类名")默认会初始化被加载类的静态属性和方法,如果不希望初始化类可以使用Class.forName("类名", 是否初始化类, 类加载器),而ClassLoader.loadClass默认不会初始化类方法。

      自定义类加载器过程

      提前写一段恶意代码,比如弹计算机。,并将其编译成class文件放置C盘下,test.class

      package com.superman.test;
      
      import java.io.IOException;
      
      public class test {
          static {
              try {
                  Runtime.getRuntime().exec("calc");
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      

      TestClassLoader.java 代码

      package com.superman.test;
      
      import java.io.IOException;
      import java.lang.reflect.Method;
      import java.nio.file.Files;
      import java.nio.file.Paths;
      
      public class TestClassLoader extends ClassLoader {
      
          // TestHelloWorld类名
          private static String testClassName = "com.superman.test.test";
      
          // TestHelloWorld类字节码
          byte[] testClassBytes;
      
          {
              try {
                  testClassBytes = Files.readAllBytes(Paths.get("C:\test.class"));
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      //    private static byte[] testClassBytes = new byte[]{
      //            -54, -2, -70, -66, 0, 0, 0, 51, 0, 17, 10, 0, 4, 0, 13, 8, 0, 14, 7, 0, 15, 7, 0,
      //            16, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100,
      //            101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101,
      //            1, 0, 5, 104, 101, 108, 108, 111, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108,
      //            97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 83, 111, 117, 114, 99,
      //            101, 70, 105, 108, 101, 1, 0, 19, 84, 101, 115, 116, 72, 101, 108, 108, 111, 87, 111,
      //            114, 108, 100, 46, 106, 97, 118, 97, 12, 0, 5, 0, 6, 1, 0, 12, 72, 101, 108, 108, 111,
      //            32, 87, 111, 114, 108, 100, 126, 1, 0, 40, 99, 111, 109, 47, 97, 110, 98, 97, 105, 47,
      //            115, 101, 99, 47, 99, 108, 97, 115, 115, 108, 111, 97, 100, 101, 114, 47, 84, 101, 115,
      //            116, 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 1, 0, 16, 106, 97, 118, 97, 47, 108,
      //            97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 3, 0, 4, 0, 0, 0, 0, 0, 2, 0, 1,
      //            0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0,
      //            1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 0, 1, 0, 9, 0, 10, 0, 1, 0, 7, 0, 0, 0, 27, 0, 1,
      //            0, 1, 0, 0, 0, 3, 18, 2, -80, 0, 0, 0, 1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 10, 0, 1, 0, 11,
      //            0, 0, 0, 2, 0, 12
      //    };
      
          @Override
          public Class<?> findClass(String name) throws ClassNotFoundException {
              // 只处理test类
              if (name.equals(testClassName)) {
                  // 调用JVM的native方法定义test类
                  return defineClass(testClassName, testClassBytes, 0, testClassBytes.length);
              }
      
              return super.findClass(name);
          }
      
          public static void main(String[] args) {
              // 创建自定义的类加载器
              TestClassLoader loader = new TestClassLoader();
      
              try {
                  // 使用自定义的类加载器加载test类
                  Class testClass = loader.loadClass(testClassName);
      
                  // 反射创建test类,等价于 test t = new test();
                  Object testInstance = testClass.newInstance();
      
                  // 反射获取hello方法
      //            Method method = testInstance.getClass().getMethod("hello");
      
                  // 反射调用hello方法,等价于 String str = t.hello();
      //            String str = (String) method.invoke(testInstance);
      //
      //            System.out.println(str);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
      }
    1. 相关阅读:
      数据结构学习记录_2019.02.26
      数据结构学习记录_2019.02.23
      数据结构学习记录_2019.02.27
      C语言学习记录_2019.02.23
      本博客所有博文密码均为“000000”
      Oracle触发器
      Oracle重载
      Oracle程序包
      Oracle函数
      Oracle存储过程
    2. 原文地址:https://www.cnblogs.com/sup3rman/p/15439371.html
    Copyright © 2011-2022 走看看