对类的植入锁定进行判断
几个可以对覆盖率跟踪的Java类定义进行instrument的API
public byte[] instrument(final ClassReader reader) {
final ClassWriter writer = new ClassWriter(reader, 0) {
@Override
protected String getCommonSuperClass(final String type1,
final String type2) {
throw new IllegalStateException();
}
};
final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory
.createFor(reader, accessorGenerator);
final ClassVisitor visitor = new ClassProbesAdapter(
new ClassInstrumenter(strategy, writer), true);
reader.accept(visitor, ClassReader.EXPAND_FRAMES);
return writer.toByteArray();
}
public byte[] instrument(final byte[] buffer, final String name)
throws IOException {
try {
return instrument(new ClassReader(buffer));
} catch (final RuntimeException e) {
throw instrumentError(name, e);
}
}
public byte[] instrument(final InputStream input, final String name)
throws IOException {
final byte[] bytes;
try {
bytes = InputStreams.readFully(input);
} catch (final IOException e) {
throw instrumentError(name, e);
}
return instrument(bytes, name);
}
public void instrument(final InputStream input, final OutputStream output,
final String name) throws IOException {
output.write(instrument(input, name));
}
private IOException instrumentError(final String name,
final Exception cause) {
final IOException ex = new IOException(
String.format("Error while instrumenting %s.", name));
ex.initCause(cause);
return ex;
}
执行流程图:

所以最终的出口在于最下面的instrument(input,output,string),下面是剩余部分代码:
public int instrumentAll(final InputStream input, final OutputStream output,
final String name) throws IOException {
final ContentTypeDetector detector;
try {
detector = new ContentTypeDetector(input);
} catch (final IOException e) {
throw instrumentError(name, e);
}
switch (detector.getType()) {
case ContentTypeDetector.CLASSFILE:
instrument(detector.getInputStream(), output, name);
return 1;
case ContentTypeDetector.ZIPFILE:
return instrumentZip(detector.getInputStream(), output, name);
case ContentTypeDetector.GZFILE:
return instrumentGzip(detector.getInputStream(), output, name);
case ContentTypeDetector.PACK200FILE:
return instrumentPack200(detector.getInputStream(), output, name);
default:
copy(detector.getInputStream(), output, name);
return 0;
}
}
private int instrumentZip(final InputStream input,
final OutputStream output, final String name) throws IOException {
final ZipInputStream zipin = new ZipInputStream(input);
final ZipOutputStream zipout = new ZipOutputStream(output);
ZipEntry entry;
int count = 0;
while ((entry = nextEntry(zipin, name)) != null) {
final String entryName = entry.getName();
if (signatureRemover.removeEntry(entryName)) {
continue;
}
zipout.putNextEntry(new ZipEntry(entryName));
if (!signatureRemover.filterEntry(entryName, zipin, zipout)) {
count += instrumentAll(zipin, zipout, name + "@" + entryName);
}
zipout.closeEntry();
}
zipout.finish();
return count;
}
private ZipEntry nextEntry(final ZipInputStream input,
final String location) throws IOException {
try {
return input.getNextEntry();
} catch (final IOException e) {
throw instrumentError(location, e);
}
}
private int instrumentGzip(final InputStream input,
final OutputStream output, final String name) throws IOException {
final GZIPInputStream gzipInputStream;
try {
gzipInputStream = new GZIPInputStream(input);
} catch (final IOException e) {
throw instrumentError(name, e);
}
final GZIPOutputStream gzout = new GZIPOutputStream(output);
final int count = instrumentAll(gzipInputStream, gzout, name);
gzout.finish();
return count;
}
private int instrumentPack200(final InputStream input,
final OutputStream output, final String name) throws IOException {
final InputStream unpackedInput;
try {
unpackedInput = Pack200Streams.unpack(input);
} catch (final IOException e) {
throw instrumentError(name, e);
}
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final int count = instrumentAll(unpackedInput, buffer, name);
Pack200Streams.pack(buffer.toByteArray(), output);
return count;
}
private void copy(final InputStream input, final OutputStream output,
final String name) throws IOException {
final byte[] buffer = new byte[1024];
int len;
while ((len = read(input, buffer, name)) != -1) {
output.write(buffer, 0, len);
}
}
private int read(final InputStream input, final byte[] buffer,
final String name) throws IOException {
try {
return input.read(buffer);
} catch (final IOException e) {
throw instrumentError(name, e);
}
}
核心关键是instrumentAll这个方法,根据文件包是class还是zip,或者gz等,不同的加载方式。
ClassInstrumenter 类
适配器为了类覆盖率跟踪。
import org.jacoco.core.internal.flow.ClassProbesVisitor;
import org.jacoco.core.internal.flow.MethodProbesVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
/**
* Adapter that instruments a class for coverage tracing.
*/
public class ClassInstrumenter extends ClassProbesVisitor {
private final IProbeArrayStrategy probeArrayStrategy;
private String className;
/**
* Emits a instrumented version of this class to the given class visitor.
* 向给定的class 访问者发出此类的instrumented版本
*
* @param probeArrayStrategy
* 该策略将用于访问探针数组
* @param cv
* 访问链中的下一位 delegate 将获得 instrumente 类
*/
public ClassInstrumenter(final IProbeArrayStrategy probeArrayStrategy,
final ClassVisitor cv) {
super(cv);
this.probeArrayStrategy = probeArrayStrategy;
}
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
this.className = name;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
InstrSupport.assertNotInstrumented(name, className);
return super.visitField(access, name, desc, signature, value);
}
@Override
public MethodProbesVisitor visitMethod(final int access, final String name,
final String desc, final String signature,
final String[] exceptions) {
InstrSupport.assertNotInstrumented(name, className);
final MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
if (mv == null) {
return null;
}
final MethodVisitor frameEliminator = new DuplicateFrameEliminator(mv);
final ProbeInserter probeVariableInserter = new ProbeInserter(access,
name, desc, frameEliminator, probeArrayStrategy);
return new MethodInstrumenter(probeVariableInserter,
probeVariableInserter);
}
@Override
public void visitTotalProbeCount(final int count) {
probeArrayStrategy.addMembers(cv, count);
}
}