有了线程上下文加载器,JNDI服务使用这个线程上下文加载器去加载所需要的SPI代码,也就是父类加载器请求子类加载器去完成类加载的动作,这种行为实际上就是打通了双亲委派模型的层次结构来逆向使用类加载器,实际上已经违背了双亲委派模型的一般性原则。但这无可奈何,Java中所有涉及SPI的加载动作基本胜都采用这种方式。例如JNDI,JDBC,JCE,JAXB,JBI等。
第三次破坏:热部署
双亲委派模型的第三次“被破坏”是由于用户对程序的动态性的追求导致的。为了实现热插拔,热部署,模块化,意思是添加一个功能或减去一个功能不用重启,只需要把这模块连同类加载器一起换掉就实现了代码的热替换。例如OSGi的出现。在OSGi环境下,类加载器不再是双亲委派模型中的树状结构,而是进一步发展为网状结构。
如果我们自己想定义一个类加载器,破坏双亲委派模型,只需要重写重写其中的loadClass方法,使其不进行双亲委派即可。
5.2.4、Tomcat类加载器架构Tomcat是主流的Java Web服务器之一,为了实现一些特殊的功能需求,自定义了一些类加载器。
Tomcat类加载器如下:
Tomcat实际上也是破坏了双亲委派模型的。
Tomact是web容器,可能需要部署多个应用程序。不同的应用程序可能会依赖同一个第三方类库的不同版本,但是不同版本的类库中某一个类的全路径名可能是一样的。如多个应用都要依赖hollis.jar,但是A应用需要依赖1.0.0版本,但是B应用需要依赖1.0.1版本。这两个版本中都有一个类是com.hollis.Test.class。如果采用默认的双亲委派类加载机制,那么无法加载多个相同的类。
所以,Tomcat破坏双亲委派原则,提供隔离的机制,为每个web容器单独提供一个WebAppClassLoader加载器。
Tomcat的类加载机制:为了实现隔离性,优先加载 Web 应用自己定义的类,所以没有遵照双亲委派的约定,每一个应用自己的类加载器——WebAppClassLoader负责加载本身的目录下的class文件,加载不到时再交给CommonClassLoader加载,这和双亲委派刚好相反。
6、JVM故障处理 6.1、基础故障处理工具 6.1.1、jps:虚拟机进程状况工具jps(JVM Process Status Tool),它的功能与 ps 命令类似,可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)
名称以及这些进程的本地虚拟机唯一 ID ( Local Virtual Machine Identifier,LVMID),类似于 ps -ef | grep java 的功能。
命令格式
jps [ options ] [ hostid ]
options:选项、参数,不同的参数可以输出需要的信息
hostid:远程查看
选项列表 描述-q 只输出进程 ID,忽略主类信息
-l 输出主类全名,或者执行 JAR 包则输出路径
-m 输出虚拟机进程启动时传递给主类 main()函数的参数
-v 输出虚拟机进程启动时的 JVM 参数
6.1.2、jstat:虚拟机统计信息监视工具
jstat(JVM Statistics Monitoring Tool),用于监视虚拟机各种运行状态信息。它可以查看本地或者远程虚拟机进程中,类加载、内存、垃圾收集、即时编译等运行时数据。
命令格式
jstat - [-t] [-h
] [ []]
vmid:如果是查看远程机器,需要按照此格式:
[protocol:][//]lvmid[@hostname[:port]/servername]
interval 和 count,表示查询间隔和次数,比如每隔 1000 毫秒查询一次进程 ID 的gc 收集情况,每次查询 5 次。jstat -gc 111552 1000 5
选项列表:
选项列表 描述-class 监视类加载、卸载数量、总空间以及类装载所耗费时长
-gc 监视 Java 堆情况,包括 Eden 区、2 个 Survivor 区、老年代、永久代或者 jdk1.8 元空间等,容量、已用空间、垃圾收集时间合计等信息
-gccapacity 监视内容与-gc 基本一致,但输出主要关注 Java 堆各个区域使用到的最大、最小空间
-gcutil 监视内容与-gc 基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与 -gcutil 功能一样,但是会额外输出导致上一次垃圾收集产生的原因
-gcnew 监视新生代垃圾收集情况
-gcnewcapacity 监视内容与 -gcnew 基本相同,输出主要关注使用到的最大、最小空间
-gcold 监视老年代垃圾收集情况
-gcoldcapacity 监视内容与 -gcold 基本相同,输出主要关注使用到的最大、最小空间
-compiler 输出即时编译器编译过的方法、耗时等信息
-printcompilation 输出已经被即时编译的方法
6.1.3、jinfo:Java配置信息工具
jinfo(Configuration Info for Java),实时查看和调整 JVM 的各项参数。在上面讲到 jps -v 指令时,可以看到它把虚拟机启动时显式的参数列表都打印
出来了,但如果想更加清晰的看具体的一个参数或者想知道未被显式指定的参数时,就可以通过 jinfo -flag 来查询了。
命令格式
jinfo [ option ] pid
6.1.4、jmap:Java内存映像工具jmap(Memory Map for Java),用于生成堆转储快照(heapdump 文件)。
jmap 的作用除了获取堆转储快照,还可以查询 finalize 执行队列、Java 堆和
方法区的详细信息。
命令格式
jmap [ option ] pid
option:选项参数
pid:需要打印配置信息的进程 ID
executable:产生核心 dump 的 Java 可执行文件
core:需要打印配置信息的核心文件
server-id:可选的唯一 id,如果相同的远程主机上运行了多台调试服务器,用此选
项参数标识服务器