前言
当执行reset、shutdown命令之后,需要对增强后的目标类进行恢复,
本篇主要对重置命令的实现进行分析。
注意:reset命令对redefine的类无效。redefine后的原来的类不能恢复。如果想重置,需要redefine原始的字节码。 原因是redefine和retransform是不同的机制,详情参见我之前写的文章。
源码分析
ResetCommand#process
@Override
public void process(CommandProcess process) {
//Instrumentation
Instrumentation inst = process.session().getInstrumentation();
//类匹配器
Matcher matcher = SearchUtils.classNameMatcher(classPattern, isRegEx);
//增强影响
EnhancerAffect enhancerAffect = null;
try {
enhancerAffect = Enhancer.reset(inst, matcher);
//响应影响
process.write(enhancerAffect.toString()).write("\n");
} catch (UnmodifiableClassException e) {
// ignore
} finally {
//结束命令
process.end();
}
}
Enhancer#reset
重置增强类
注意:
当前方法中的transform()返回null,reset只是恢复原字节码内容,无需定义任何增强逻辑。
public static synchronized EnhancerAffect reset(
final Instrumentation inst,
final Matcher classNameMatcher) throws UnmodifiableClassException {
//增强影响
final EnhancerAffect affect = new EnhancerAffect();
//被增强的类的集合
final Set<Class<?>> enhanceClassSet = new HashSet<Class<?>>();
//从已增强类的缓存中查找要reset的类
for (Class<?> classInCache : classBytesCache.keySet()) {
//匹配目标类
if (classNameMatcher.matching(classInCache.getName())) {
enhanceClassSet.add(classInCache);
}
}
//定义字节码转换器
final ClassFileTransformer resetClassFileTransformer = new ClassFileTransformer() {
@Override
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
return null;
}
};
try {
//批量增强
enhance(inst, resetClassFileTransformer, enhanceClassSet);
logger.info("Success to reset classes: " + enhanceClassSet);
} finally {
//因为已经目标类已经重置,将其从缓存中移除。
for (Class<?> resetClass : enhanceClassSet) {
classBytesCache.remove(resetClass);
affect.cCnt(1);
}
}
return affect;
}
Enhancer#enhance
批量重置。
public static void enhance(Instrumentation inst, ClassFileTransformer transformer, Set<Class<?>> classes)
throws UnmodifiableClassException {
try {
//添加.class文件转换器
inst.addTransformer(transformer, true);
int size = classes.size();
Class<?>[] classArray = new Class<?>[size];
//复制字节码到classArray
arraycopy(classes.toArray(), 0, classArray, 0, size);
if (classArray.length > 0) {
inst.retransformClasses(classArray);
}
} finally {
//增强完毕,移除transformer
inst.removeTransformer(transformer);
}
}