在没有源码的情况,如何修改引用的第三方jar中的方法来适应自己的业务需求

1,455 阅读4分钟

业务背景

我有个业务,引用了第三方的包来实现,然后这个第三方的包中基本都能满足我的业务需求。但是,其中有某个方法,或者某个类的一些方法,跟我的需求不匹配。我想改一下这个方法,但是又没有这个包的源码(如果你直接反编译然后再重新打包,每次有变动就再修改再打包,那当我没说,文章到此结束哈哈)。

比如,你引用了一个数字处理的第三方包,里面提供了对数据各种丰富的操作,but,其中有个A方法是调B方法返回的所有正数进行操作的,但你想要的是A方法中处理的数是非负数,也就是0也能加入进去。此时因为各种依赖的原因,你只能用A方法来处理数据,那么这时候,我们就需要修改B方法,让它把0加上。

代码

一.先上代码先,因为上面的故事是虚构的,所以我需要自己手敲一个小demo。 首先是假设我们引用的第三方包,使用idea建一个项目然后打成包放进项目的lib文件夹中或者使用maven,我这里用maven

jar包结构

image.png

Ajar类

/**
* jar包中的a类<br>
* jar包中的a类<br>
*
* @author jasion
* @date 2021-10-28 16:08
*/
package com.xiaojian;

public class Ajar {
  public void say(){
      System.out.println("我是jar包中的say()方法");
  }
}

AUseJar类

/**
 * 使用Ajar这个类的包<br>
 * 使用Ajar这个类的包<br>
 *
 * @author jasion
 * @date 2021-10-28 16:18
 */
package com.xiaojian;

public class AUseJar {
    public void useA(){
        Ajar ajar=new Ajar();
        ajar.say();
    }
}

这个jar包中就是AuserJar类中的useA方法,调用了Ajar类中的say方法,简单来说就是在同一个jar包中,我用一个类调用了另一个类的方法(调用同类中的同个方法也是一样的效果,只不过是下面重写哪个类的区别而已)

二.此时我有个工程项目,导入了这个包

image.png

image.png

然后在这个项目里面建了个测试类Test,用来调用jar包中的类的方法

/**
 * 主要测试类<br>
 * 主要测试类<br>
 *
 * @author jasion
 * @date 2021-10-28 16:13
 */
package com.jasion;

import com.xiaojian.AUseJar;
import com.xiaojian.Ajar;

public class Test {
    public static void main(String[] args) {
        //直接使用替换的类
//        Ajar ajar = new Ajar();
//        ajar.say();

        //间接使用替换的类
        AUseJar aUseJar=new AUseJar();
        aUseJar.useA();
//        System.out.println(System.getProperty("java.ext.dirs"));
//        System.out.println(System.getProperty("java.class.path"));
       
    }
}

此时我们跑下这个测试类,会打印出什么呢? 没错,就是

image.png

到这里为止,都是正常的操作。那这时候,假设我想在不改变jar包源码的情况下,重写Ajar中的say()方法,要怎么弄呢? 三.这个时候只需要我们在我们业务项目的建立一个跟jar包Ajar类相同的包路径以及相同的类名,然后重写say()方法就行了。

image.png

/**
 * 本地的Ajar<br>
 * 本地的Ajar<br>
 *
 * @author jasion
 * @date 2021-10-28 16:14
 */
package com.xiaojian;

public class Ajar {
    public void say(){
        System.out.println("我是业务项目中的say()方法");
    }
}

这个时候我们再重新跑一下测试类中的方法,会打印出什么呢?

image.png

jar包中的say方法被替换掉了!很强有没有。

结论

先说结论:如果想要替换jar包中的某个类或者某个方法,只需要在项目中创建一个相同包路径,相同类名的类就能够替换调了,而不需要修改jar包的源码。

原因

首先看到我测试类里面有个打印某个属性的代码

image.png

这个是怎么来的呢,这个实际上是jdk源码的应用类加载器中的。

image.png 这个路径记录应用类加载器加载的类路径,也就是应用类加载器要加载哪些路径下的类。我们把它跑一下,我这里使用了换行符号换了下,得到这个路径。

image.png image.png

我们可以看到,对应应用类加载器来说,它是先去加载本项目的classpath下面的类,再去加载lib中引用的包中的中类。(本来想去看下顺序加载的源码的,结构是本地方法实现的看不了,或许是我没找到~)根据类加载的双亲委派机制(类加载的不拓展开了,后面有空再写一篇),因为Ajar这个类已经加载过了,所以当AUserJar用到Ajar这个类的时候,会从应用类加载器缓存中查找并返回业务项目中的Ajar而不会重新加载jar包里面的。