Javassit ClassPool.getDefault的问题

2019-11-30  本文已影响0人  健忘仙森

在Android开发中,我们经常通过Gradle Plugin配合Android Gradle Plugin提供的Tranform API,并应用Javassit字节码编辑库在Android打包过程中做一些特殊操作。例如:自动埋点,热修复等。

Javassit提供了一个方便获取ClassPool的方法,ClassPool.getDefault()它是个单列对象

当你在使用assemble命令打包你的Android应用时,默认会执行assembleDebugassembleRelease,如果你增加了定义的buildTypes或者flavors,所有的assembleXXX命令都会执行。因此assemble多次调用void transform(TransformInvocation transformInvocation)方法。

此时,如果你是使用ClassPool.getDefault()来存放你需要操作的Class,并且在自定义Transform中对CtClass应用writeFile()toClass()或者toByteCode()方法将其转换成Class文件,那么Javassist就会冻结(frozen)这个CtClass对象,之后就不能修改这个CtClass对象了。所以transform方法第二次执行时,我们在对ClassPool.getDefault()里面的CtClasswriteFile()toClass()或者toByteCode()操作就会发生xxx class is frozen.的错误。

Javassit的此异常是为了警告开发者不要修改已经被JVM加载的class文件,因为JVM不允许重新加载一个类。

解决方法:不要使用ClassPool.getDefault()来获取ClassPool,通过ClassPool classPool = new ClassPool(true)的方式自己创建,因为每次都是新创建的ClassPool,所以在执行assemble后多次调用void transform(TransformInvocation transformInvocation)方法不会出现上述异常。

上一篇下一篇

猜你喜欢

热点阅读