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]);
      }
    
    }

     

     
posted @ 2017-03-21 00:38  jieyuefeng  阅读(136)  评论(0编辑  收藏  举报