Java类加载机制深入理解及Arthas实战

15 篇文章 0 订阅
2 篇文章 0 订阅

从一次Java类加载冲突说起

之前在网易做一个项目时,发现了如下java包是重复引入有冲突
在这里插入图片描述

分析

学会了用Arthas工具(Arthas 是Alibaba开源的Java诊断工具)分析加载的类sc -df org.apache.commons.codec.*,还有dependency.txt,目前看:

1.有直接引用的,用直接引用的

2.都是间接的,用最新的

dependency.txt中如下httpcore确实被两个引用到了


[[1;34mINFO[m] |  +- org.apache.httpcomponents:httpcore:jar:4.4.9:compile

[[1;34mINFO[m] |  \- commons-codec:commons-codec:jar:1.11:compile

[[1;34mINFO[m] +- commons-io:commons-io:jar:1.3.2:compile

[[1;34mINFO[m] +- com.netease.cloud:nos-sdk-java:jar:1.2.6:compile

[[1;34mINFO[m] |  +- org.apache.httpcomponents:httpcore:pom:4.1:compile


那么Java的类加载机制到底是怎么样的?

如上的例子,说明引入同名的jar包的情况是存在的,可能有人奇怪为什么会这样,这正是Java类加载机制需要回答的问题。如下图简单明了说明了类加载机制过程和优先级
在这里插入图片描述
我们可以用一段代码验证一下

// First, check if the class has already been loaded 先检查有没有加载过,加载过就不用在加载了,简单
Class c = findLoadedClass(name); 
if (c == null) {  --如果还没加载
        long t0 = System.nanoTime(); 
        try {                        
             if (parent != null) {                   c = parent.loadClass(name, false);                          } 
			 else {                             c = findBootstrapClassOrNull(name);                               } 
			 //如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)                            
		} catch (ClassNotFoundException e) {
		    ...
        }               
        return c;

深入理解Java类加载机制

如果把JVM比喻成一个俱乐部,那么这个俱乐部的会员都是谁请来的呢?类似于传销模式那样

  • 首先,特点就是灵活。没有死板的规定,从一个文件中读取,而是多种途径,由应用自己决定。体现了“去中心化”的邀请

  • 新会员加入时,引荐的类都必须先转给父辈,父类来加载,加载不成功才由本类加载;父辈的老朋友,必须由父辈邀请,而且邀请前看看他是否已经在俱乐部了,这样的好处是

    • 确保不重复入会

    • 老朋友是父类的,不会加载不一样的

  • 这个机制是保证“增量优化”

  • 由不同ClassLoader对象加载的同名类属于不同类

JVM看来是个松散俱乐部,你引荐的和他引荐的可能是相同人或者同名人,不要紧,你的圈子里,只认由加载你的加载器加载的那个类

那么问题来了,为什么Tomcat不遵守这个规定?

双亲委派机制不是java的强制规范,但是是一种推荐标准

好处如下所说,一个强规则的等级社会,确保基础的类,比如java.lang.Object不会出现紊乱

那么tomcat为什么要故意绕开这种机制,因为具体情况不同:

  1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。 如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的累加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份

  2. 部署在同一个web容器中相同的类库相同的版本可以共享。

  3. web容器也有自己依赖的类库,不能于应用程序的类库混淆

  4. jsp热修改问题

我们想我们要怎么实现jsp文件的热修改(楼主起的名字),jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的。那么怎么办呢?我们可以直接卸载掉这jsp文件的类加载器,所以你应该想到了,每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。


Arthas实战分析

首先,Arthas非常好用(但是注意尽量避免用到生产环境,踩过坑,对生产环境性能和稳定性有影响,毕竟其原理是替换生产在运行的class)
使用过后分析,现在jvm中实际运行的类,不再是jar包中了,很多都是动态代理的
为什么?公共的功能统一加!!! 比如

  • 日志多打一些

  • 执行时间统计出来

  • 统一走某个session验证

实战中有很多例子,值得思考的是,就算动态代理更慢,但是哨兵和SpringBoot的都选了动态代理;而不选择快但是麻烦的静态代理(编译时就确定)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值