一、双亲委派模式jdk提供了3个加载器,未来我们还能自定义加载器
-
jdk同时提供了双亲委派机制,使得多个加载器可以更合理的协作应用
-
当我们在程序中需要使用一个类时,会先向最底层的类加载器申请这个类(app)
-
如果app加载器加载过这个类,就会返回该类的Class对象
-
如果app没有加载过这个类,app会向其父级加载器(ext)申请这个类
-
如果ext加载过就返回这个类,如果没有加载过这个类,继续想起父级(Bootstrap)申请
-
如果bootstrap加载过就返回这个类,如果没有加载过,就尝试加载
-
如果在bootstrap的加载范围内,则加载这个类
-
如果不再bootstrap的加载范围内, 尝试让ext加载
-
如果在ext加载范围内,就让ext加载。如果不在就尝试让app加载
-
如果在app加载范围内,就让app加载,否则就抛出ClassNotFoundException
-
-
注意:app 和 ext 和 bootstrap是逻辑上的子父级关系,不是真正 的extends继承关系
-
双亲委派机制的优点
-
防止核心类被篡改。
-
方式类重复加载
-
防止在核心包中扩展类(沙箱机制)
-
二、自定义类加载器
-
哪些情况需要自定义类加载器呢?
-
扩展加载源 ,如:从网络中加载类库
-
类的隔离
-
类信息的解密
-
-
如何自定义类加载器
-
自定义加载器类, 继承ClassLoader
-
重写方法
-
可以重写
loadClass
方法,但不推荐。因为该方法中提供了双亲委派机制如果重写该方法,相等于破坏了双亲委派机制。
-
可以重写
findClass
方法,根据需求,去指定的地方获取类文件信息以byte[]的形式装载找到的类信息
-
还有一个很重要的方法
defineClass()
,用来将字节码内容进行一系列的处理,并存储在方法区,并生成Class对象所以在findClass之后,一定要调用该方法。
-
-
使用类加载器
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(); }
-