java的动态代理都是拦截自己写的代码,我想拦截第三方库的代码,比如
//这个第三方库的代码
x.show();
我需要在它执行的前后加上自己的代码。
第三方库没有提供钩子。也没有拓展的可能。
java的动态代理都是拦截自己写的代码,我想拦截第三方库的代码,比如
//这个第三方库的代码
x.show();
我需要在它执行的前后加上自己的代码。
第三方库没有提供钩子。也没有拓展的可能。
拦截第三方库的代码,和拦截自己写的代码,用法是一样的。
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;
}
}
}
3 回答2.6k 阅读✓ 已解决
3 回答4.1k 阅读✓ 已解决
8 回答3.6k 阅读
4 回答2.8k 阅读✓ 已解决
2 回答2.6k 阅读✓ 已解决
3 回答2.5k 阅读✓ 已解决
3 回答1.7k 阅读✓ 已解决
结合前面几位的回答,我给出几个我常用的处理办法,由简单到复杂
一、通过类加载器直接覆盖
Java中的类加载器,当前模块
Classpath
的类优先于其他(Classpath
)模块的类,利用这个特点,你可以在你的项目中复制一份第三方的类,包名.类名完全一模一样,但是某个函数或者属性变了(签名没变即可),编译后,你的代码就会覆盖三方代码。该方式最简单,最有效,最直接。
二、私服或本地jar改源码
如果三方库是开源的,你可以
clone
下来代码,修改后,打入自己的私服,或者直接lib的形式引入。三、设计模式
设计模式中有个代理模式和装饰器模式,假如你的调用链非常的短,你能干预调用过程,你可以通过继承、重写、组合的形式,将目标类装饰一层
这种适用于修改函数不多,调用链短,访问修饰符开放
四、反射修改对象
java都是对象,如果调用层级过深,调用的某个对象来自类中的某个属性,你可以结合第三步,在即将调用到目标函数时,将某个属性的实例使用反射改了
五、有IOC容器/SPI支撑用代理
假如目标三方类是单例,且依靠IOC容器,通过
SPI
,Spring
,dubbo
的SPI等创建的对象,你可以在实际调用前,将目标类对象通过动态代理、AOP,装饰,反射等修改,也能达到效果六、终极方案之
Java Agent
如果上面的方案你都不想用,可以使用agent技术,在java -jar启动时,注入自己的agent库,可修改任意代码,非常强大,具体方式自行学习。
七、修改字节码
在代码运行前,通过三方字节码库,将class直接修改,比较复杂。