java能拦截第三方代码执行吗?

java的动态代理都是拦截自己写的代码,我想拦截第三方库的代码,比如
//这个第三方库的代码
x.show();
我需要在它执行的前后加上自己的代码。
第三方库没有提供钩子。也没有拓展的可能。

阅读 1k
3 个回答
✓ 已被采纳

结合前面几位的回答,我给出几个我常用的处理办法,由简单到复杂

一、通过类加载器直接覆盖

Java中的类加载器,当前模块Classpath的类优先于其他(Classpath)模块的类,利用这个特点,你可以在你的项目中复制一份第三方的类,包名.类名完全一模一样,但是某个函数或者属性变了(签名没变即可),编译后,你的代码就会覆盖三方代码。

该方式最简单,最有效,最直接。

二、私服或本地jar改源码

如果三方库是开源的,你可以clone下来代码,修改后,打入自己的私服,或者直接lib的形式引入。

三、设计模式

设计模式中有个代理模式和装饰器模式,假如你的调用链非常的短,你能干预调用过程,你可以通过继承、重写、组合的形式,将目标类装饰一层

class TargetPlus extends Target {
    private Target  target;

public TargetPlus (Target target){
    this.target = Target;
}

// .... 其他装饰函数

}

这种适用于修改函数不多,调用链短,访问修饰符开放

四、反射修改对象

java都是对象,如果调用层级过深,调用的某个对象来自类中的某个属性,你可以结合第三步,在即将调用到目标函数时,将某个属性的实例使用反射改了

class A {
    private B b;


    public void run(){
        b.method();
    }
}

void run(){
  A a = new A();
  // 反射将a中b的实例修改为替换的实例。
  a.run();
}

五、有IOC容器/SPI支撑用代理

假如目标三方类是单例,且依靠IOC容器,通过SPI,Spring,dubbo的SPI等创建的对象,你可以在实际调用前,将目标类对象通过动态代理、AOP,装饰,反射等修改,也能达到效果

六、终极方案之Java Agent

如果上面的方案你都不想用,可以使用agent技术,在java -jar启动时,注入自己的agent库,可修改任意代码,非常强大,具体方式自行学习。

七、修改字节码

在代码运行前,通过三方字节码库,将class直接修改,比较复杂。

拦截第三方库的代码,和拦截自己写的代码,用法是一样的。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface TargetInterface {
    void targetMethod();
}

class TargetImplementation implements TargetInterface {
    @Override
    public void targetMethod() {
        System.out.println("Original method execution");
    }
}

class ProxyHandler implements InvocationHandler {
    private Object target;

    public ProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method invocation");
        Object result = method.invoke(target, args);
        System.out.println("After method Invocation");
        return result;
    }
}

public class DynamicProxyExample {
    public static void main(String[] args) {
        TargetInterface target = new TargetImplementation();
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
                TargetInterface.class.getClassLoader(),
                new Class[]{TargetInterface.class},
                new ProxyHandler(target));

        proxy.targetMethod();
    }
}

这段代码,是调用的自己的代码,换成其他任意jar里类方法,用法也一样的。

如果三方库的类可以注册成spring的bean,可以直接用@Aspect进行拦截

@Component
@Aspect
public class ThirdAspect {

    @Around("execution(* com.xxx.xxx.xxx.xxx.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        try {
            //拦截逻辑
            return pjp.proceed(pjp.getArgs());
        } catch (Exception e) {
            //异常逻辑
            throw e;
        }
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏