• classloader 结构,是否可以自己定义一个 java.lang.String 类,为什么? 双亲代理机制。


    参考文献:

      http://www.cnblogs.com/leesf456/p/5269545.html   

      http://www.cnblogs.com/doit8791/p/5820037.html

    1. 双亲委派模型

      从虚拟机角度看,只存在两种类加载器:1. 启动类加载器。2. 其他类加载器。从开发人员角度看,包括如下类加载器:1. 启动类加载器。2. 扩展类加载器。3. 应用程序类加载器。4. 自定义类加载器。

      ① 启动类加载器,用于加载Java API,加载<JAVA_HOME>lib目录下的类库。

      ② 扩展类加载类,由sun.misc.Launcher$ExtClassLoader实现,用于加载<JAVA_HOME>libext目录下或者被java.ext.dirs系统变量指定路径下的类库。

      ③ 应用程序类加载器,也成为系统类加载器,由sun.misc.Launcher$AppClassLoader实现,用于加载用户类路径(ClassPath)上所指定的类库。

      ④ 自定义类加载器,继承系统类加载器,实现用户自定义加载逻辑。

      各个类加载器之间是组合关系,并非继承关系。

      当一个类加载器收到类加载的请求,它将这个加载请求委派给父类加载器进行加载,每一层加载器都是如此,最终,所有的请求都会传送到启动类加载器中。只有当父类加载器自己无法完成加载请求时,子类加载器才会尝试自己加载。

      双亲委派模型可以确保安全性,可以保证所有的Java类库都是由启动类加载器加载。如用户编写的java.lang.Object,加载请求传递到启动类加载器,启动类加载的是系统中的Object对象,而用户编写的java.lang.Object不会被加载。如用户编写的java.lang.virus类,加载请求传递到启动类加载器,启动类加载器发现virus类并不是核心Java类,无法进行加载,将会由具体的子类加载器进行加载,而经过不同加载器进行加载的类是无法访问彼此的。由不同加载器加载的类处于不同的运行时包。所有的访问权限都是基于同一个运行时包而言的。 

      当一个类加载器收到类加载的请求,它将这个加载请求委派给父类加载器进行加载,每一层加载器都是如此,最终,所有的请求都会传送到启动类加载器中。只有当父类加载器自己无法完成加载请求时,子类加载器才会尝试自己加载。

      双亲委派模型可以确保安全性,可以保证所有的Java类库都是由启动类加载器加载。如用户编写的java.lang.Object,加载请求传递到启动类加载器,启动类加载的是系统中的Object对象,而用户编写的java.lang.Object不会被加载。如用户编写的java.lang.virus类,加载请求传递到启动类加载器,启动类加载器发现virus类并不是核心Java类,无法进行加载,将会由具体的子类加载器进行加载,而经过不同加载器进行加载的类是无法访问彼此的。由不同加载器加载的类处于不同的运行时包。所有的访问权限都是基于同一个运行时包而言的。 

    2.为什么要使用这种双亲委托模式呢?
    因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
    考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。
    思考:假如我们自己写了一个java.lang.String的类,我们是否可以替换调JDK本身的类?
    答案是否定的。我们不能实现。为什么呢?我看很多网上解释是说双亲委托机制解决这个问题,其实不是非常的准确。因为双亲委托机制是可以打破的,你完全可以自己写一个classLoader来加载自己写的java.lang.String类,但是你会发现也不会加载成功,具体就是因为针对java.*开头的类,jvm的实现中已经保证了必须由bootstrp来加载。
     
     3.定义自已的ClassLoader
     
    既然JVM已经提供了默认的类加载器,为什么还要定义自已的类加载器呢?
     
    因为Java中提供的默认ClassLoader,只加载指定目录下的jar和class,如果我们想加载其它位置的类或jar时,比如:我要加载网络上的一个class文件,通过动态加载到内存之后,要调用这个类中的方法实现我的业务逻辑。在这样的情况下,默认的ClassLoader就不能满足我们的需求了,所以需要定义自己的ClassLoader。
     
    定义自已的类加载器分为两步:
     
    1、继承java.lang.ClassLoader
     
    2、重写父类的findClass方法
     
    读者可能在这里有疑问,父类有那么多方法,为什么偏偏只重写findClass方法?
     
    因为JDK已经在loadClass方法中帮我们实现了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法就会调用findClass方法来搜索类,所以我们只需重写该方法即可。如没有特殊的要求,一般不建议重写loadClass搜索类的算法。
  • 相关阅读:
    导出csv 随便记录
    mysql 5.7.27 win64 安装步骤
    mysql 报错ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executin
    Mysql 基本命令
    遇到summernote编辑器的坑,解决上传图片性能问题。
    ajax提交json格式数组
    idea导入eclipse项目,tomcat启动报错org.apache.catalina.deploy.WebXml addFilter
    Spring(一)
    MyBatis源码分析(一)--SqlSessionFactory的生成
    MyBatis(八)--逆向工厂(generatorSqlmapCustom)
  • 原文地址:https://www.cnblogs.com/liuheng0315/p/7160794.html
Copyright © 2020-2023  润新知