问题
有时候我们调用第三方依赖jar包,发现代码有bug存在,如果找到了代码错误所在,可以Github反馈给作者进行修复,但是需要时间等待作者修复后使用,所以需要当下解决这个问题:
解决办法
1.自己打包
将源码clone下来,修复错误,然后自己打包使用;
2.功能提取
将有问题的功能(类及方法)提取出来,单独修改使用;这样做比较复杂,因为可能用到的某个方法层层依赖于其他类,需要把依赖的全部提取出来;
3.字节码增强
使用ASM,Javassist,Byte Buddy等字节码增强技术,在运行中修改字节码,达到改变功能及增强目的;
1.修改普通类的方法
原方法
public class RandomIntTest {
public int randomInt() {
return new Random().nextInt(10);
}
}
修改字节码运行
public static void main(String[] args) throws NotFoundException, CannotCompileException {
ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
CtClass ctClass = classPool.get("demo.RandomIntTest");
CtMethod ctMethod = ctClass.getDeclaredMethod("randomInt");
ctMethod.setBody("return -999;");
ctClass.toClass();
ctClass.detach();
int i = new RandomIntTest().randomInt();
System.out.println(i);
}
2.修改springboot中的bean方法
原bean
@Service
public class RandomIntTest {
public int randomInt() {
return new Random().nextInt(10);
}
}
启动方法里面进行修改:
@SpringBootApplication
public class TomcatTestApplication {
public static void main(String[] args) {
init();
SpringApplication.run(TomcatTestApplication.class, args);
}
public static void init() {
try {
ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
CtClass ctClass = classPool.get("com.example.tomcattest.service.RandomIntTest");
CtMethod ctMethod = ctClass.getDeclaredMethod("randomInt");
ctMethod.setBody("return -999;");
ctClass.toClass();
ctClass.detach();
} catch (Exception e) {
e.printStackTrace();
}
}
}
直接调用
@RestController
public class TestController {
@Autowired
RandomIntTest test;
@GetMapping("/Javassist")
public Integer Javassist() throws Exception {
return test.randomInt();
}
}
还可以使用:
这是整个spring容器在刷新之前初始化ConfigurableApplicationContext的回调接口,简单来说,就是在容器刷新之前调用此类的initialize方法。这个点允许被用户自己扩展。用户可以在整个spring容器还没被初始化之前做一些事情。在最开始激活一些配置,或者利用这时候class还没被类加载器加载的时机,进行动态字节码注入等操作。
public class TestApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("[ApplicationContextInitializer]");
}
}
3.使用热插拔更新HotSwapper(启动命令开启远程调试,添加-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8080)
本文由 GY 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
2022/08/12 17:26