zoukankan      html  css  js  c++  java
  • ClassLoader

    Java类加载器

    定义

    虚拟机设计团队把类加载阶段中的”通过一个类的全限定名来获取描述此类的二进制字节流“这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为”类加载器

    类加载器在类层次划分、OSGi、热部署、代码加密等领域大放异彩。

     

    分类

    类加载器的分类:

    • 启动类加载器:Bootstrap ClassLoader,使用C++语言实现,负责加载<JAVA_HOME>/lib目录下或 -Xbootclasspath 参数指定的路径

    • 扩展类加载器:Extension ClassLoader,使用Java语言实现,负责加载<JAVA_HOME>/lib/ext目录下或被java.ext.dirs系统变量所指定的路径

    • 应用程序类加载器:Application ClassLoader,使用Java语言实现,负责加载用户类路径(classpath),也称为系统类加载器

       

      双亲委派

      工作过程:如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到启动类加载器中,只有当父加载器反馈无法完成这个加载请求时,子加载器才会尝试自己去加载,

      好处:Java类随着它的类加载器一起具备了一种带优先级的层次关系,保证了基础类的唯一性

      三次被破坏:

      1. JDK1.0中被覆盖的loadClass方法(JDK1.2之后不建议覆盖loadClass,而改用findClass方法,loadClass会在父类加载失败时调用findClass)

      2. 为了实现JNDI接口的服务提供者(SPI)引入了线程上下文类加载器(Thread Context ClassLoader),该类加载器如果未设置则从父线程继承,默认为应用程序类加载器

      3. Java模块化,OSGi实现模块化热部署的关键则是它自定义的类加载机制的实现。每个程序模块(OSGi中称为Bundle)都有一个自己的类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起还掉以实现代码的热替换

       

      自定义类加载器示例

      // /Users/frank/Documents/Develop/classes/com/yfsoft/java/model/HelloWorld.java
      package com.yfsoft.java.model;
      
      public class HelloWorld {
      
        public void hello() {
          System.out.println("Fuck You");
        }
      
      }
      
      // 单独编译
      // javac HelloWorld.java
      package com.yfsoft.java;
      
      import org.apache.commons.io.FileUtils;
      
      import java.io.File;
      import java.io.IOException;
      import java.lang.reflect.InvocationTargetException;
      
      public class TestClassLoader {
      
        // 继承自ClassLoader
        private static class MyClassLoader extends ClassLoader {
      
          private String dir;
      
          public MyClassLoader(String dir) {
            this.dir = dir;
          }
      
          // 重写findClass方法,读取class文件内容并通过defineClass获取Class对象
          @Override
          protected Class<?> findClass(String name) throws ClassNotFoundException {
      
            try {
              byte[] bytes = FileUtils.readFileToByteArray(new File(dir, name + ".class"));
              return defineClass(null, bytes, 0, bytes.length);
            } catch (IOException e) {
              throw new ClassNotFoundException("not class file found '" + name + ".class' in '" + dir + "' ");
            }
      
          }
      
        }
      
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
          MyClassLoader loader = new MyClassLoader("/Users/frank/Documents/Develop/classes/");
      
          // 通过类的全限定名获取
          // 一个类的全限定名是将类全名的"."全部换为"/"
          Class<?> cls = loader.loadClass("com/yfsoft/java/model/HelloWorld");
      
          Object obj = cls.newInstance();
      
          cls.getMethod("hello", new Class[0]).invoke(obj, new Object[0]);
        }
      
      }
       
  • 相关阅读:
    穷举
    菱形
    docker安装cloudera manager,切换cloudera-scm用户报错can not open session
    修改cloudera manager的端口号
    postgresql拓展if、ifnull、group_concat函数
    clion调试postgresql
    Java面向切面原理与实践
    Spring-boot非Mock测试MVC,调试启动tomcat容器
    spring-cloud-feign 使用@RequetParam报错QueryMap parameter must be a Map: class java.lang.String
    linux虚拟机拓展大小
  • 原文地址:https://www.cnblogs.com/jieyuefeng/p/6592495.html
Copyright © 2011-2022 走看看