双亲委派模式与 自定义类加载器

 一、双亲委派模式jdk提供了3个加载器,未来我们还能自定义加载器

  • jdk同时提供了双亲委派机制,使得多个加载器可以更合理的协作应用

    1. 当我们在程序中需要使用一个类时,会先向最底层的类加载器申请这个类(app)

    2. 如果app加载器加载过这个类,就会返回该类的Class对象

    3. 如果app没有加载过这个类,app会向其父级加载器(ext)申请这个类

    4. 如果ext加载过就返回这个类,如果没有加载过这个类,继续想起父级(Bootstrap)申请

    5. 如果bootstrap加载过就返回这个类,如果没有加载过,就尝试加载

    6. 如果在bootstrap的加载范围内,则加载这个类

    7. 如果不再bootstrap的加载范围内, 尝试让ext加载

    8. 如果在ext加载范围内,就让ext加载。如果不在就尝试让app加载

    9. 如果在app加载范围内,就让app加载,否则就抛出ClassNotFoundException

  • 注意:app 和 ext 和 bootstrap是逻辑上的子父级关系,不是真正 的extends继承关系

  • 双亲委派机制的优点

    1. 防止核心类被篡改。

    2. 方式类重复加载

    3. 防止在核心包中扩展类(沙箱机制)

 二、自定义类加载器

  • 哪些情况需要自定义类加载器呢?

    1. 扩展加载源 ,如:从网络中加载类库

    2. 类的隔离

    3. 类信息的解密

  • 如何自定义类加载器

    1. 自定义加载器类, 继承ClassLoader

    2. 重写方法

      • 可以重写loadClass方法,但不推荐。因为该方法中提供了双亲委派机制

        如果重写该方法,相等于破坏了双亲委派机制。

      • 可以重写findClass方法,根据需求,去指定的地方获取类文件信息

        以byte[]的形式装载找到的类信息

      • 还有一个很重要的方法defineClass(),用来将字节码内容进行一系列的处理,并存储在方法区,并生成Class对象

        所以在findClass之后,一定要调用该方法。

    3. 使用类加载器

      public class MyClassLoader extends ClassLoader{
      
          //name 一般就是com.buka.User 类路径
          //可以根据这个类路径确定最重要加载的目标类
          @Override
          protected Class findClass(String name) throws ClassNotFoundException {
              try {
                  Socket link = new Socket("localhost",6666);
                  InputStream is = link.getInputStream();
                  //存储所有读取到的字节信息
                  //本来是需要使用字节数组
                  //但无法确定从网络中读取字节的数量,就不知道要定义多长的字节数组
                  //可以使用ByteArrayOutputStream
                  ByteArrayOutputStream bos = new ByteArrayOutputStream();
      
                  byte[] bs =new byte[010];
                  while(true){
                      int len = is.read(bs);
                      if(len == -1){
                          break ;
                      }
                      bos.write(bs,0,len);
                  }
      
                  byte[] content = bos.toByteArray();
      
                 return  super.defineClass("X",content,0,content.length);
      
              } catch (IOException e) {
                  throw new RuntimeException(e);
              }
          }
      }
      public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
          MyClassLoader loader  = new MyClassLoader();
          Class c = loader.loadClass("X");
          c.newInstance();
      }

你可能感兴趣的:(spring,前端,java)