在本文当中,我们的关注点在于 InstrumentationImpl
、transformer 和 TransformerManager
三者的关系。
InstrumentationImpl
class info
sun.instrument.InstrumentationImpl
实现了 java.lang.instrument.Instrumentation
接口:
public class InstrumentationImpl implements Instrumentation {
}
fields
public class InstrumentationImpl implements Instrumentation {
private final TransformerManager mTransformerManager;
private TransformerManager mRetransfomableTransformerManager;
// ...
}
constructor
public class InstrumentationImpl implements Instrumentation {
private InstrumentationImpl(long nativeAgent,
boolean environmentSupportsRedefineClasses,
boolean environmentSupportsNativeMethodPrefix) {
mTransformerManager = new TransformerManager(false);
mRetransfomableTransformerManager = null;
// ...
}
}
xxxTransformer
addTransformer
public class InstrumentationImpl implements Instrumentation {
public void addTransformer(ClassFileTransformer transformer) {
addTransformer(transformer, false);
}
public synchronized void addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
if (transformer == null) {
throw new NullPointerException("null passed as 'transformer' in addTransformer");
}
if (canRetransform) {
if (!isRetransformClassesSupported()) {
throw new UnsupportedOperationException("adding retransformable transformers is not supported in this environment");
}
if (mRetransfomableTransformerManager == null) {
mRetransfomableTransformerManager = new TransformerManager(true);
}
mRetransfomableTransformerManager.addTransformer(transformer);
if (mRetransfomableTransformerManager.getTransformerCount() == 1) {
setHasRetransformableTransformers(mNativeAgent, true);
}
}
else {
mTransformerManager.addTransformer(transformer);
}
}
}
removeTransformer
public class InstrumentationImpl implements Instrumentation {
public synchronized boolean removeTransformer(ClassFileTransformer transformer) {
if (transformer == null) {
throw new NullPointerException("null passed as 'transformer' in removeTransformer");
}
TransformerManager mgr = findTransformerManager(transformer);
if (mgr != null) {
mgr.removeTransformer(transformer);
if (mgr.isRetransformable() && mgr.getTransformerCount() == 0) {
setHasRetransformableTransformers(mNativeAgent, false);
}
return true;
}
return false;
}
}
findTransformerManager
public class InstrumentationImpl implements Instrumentation {
private TransformerManager findTransformerManager(ClassFileTransformer transformer) {
if (mTransformerManager.includesTransformer(transformer)) {
return mTransformerManager;
}
if (mRetransfomableTransformerManager != null &&
mRetransfomableTransformerManager.includesTransformer(transformer)) {
return mRetransfomableTransformerManager;
}
return null;
}
}
transform
public class InstrumentationImpl implements Instrumentation {
private byte[] transform(ClassLoader loader,
String classname,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer,
boolean isRetransformer) {
TransformerManager mgr = isRetransformer ? mRetransfomableTransformerManager : mTransformerManager;
if (mgr == null) {
return null; // no manager, no transform
}
else {
return mgr.transform(loader, classname, classBeingRedefined, protectionDomain, classfileBuffer);
}
}
}
TransformerInfo
private class TransformerInfo {
final ClassFileTransformer mTransformer;
String mPrefix;
TransformerInfo(ClassFileTransformer transformer) {
mTransformer = transformer;
mPrefix = null;
}
ClassFileTransformer transformer() {
return mTransformer;
}
String getPrefix() {
return mPrefix;
}
void setPrefix(String prefix) {
mPrefix = prefix;
}
}
TransformerManager
class info
public class TransformerManager {
}
fields
public class TransformerManager {
private TransformerInfo[] mTransformerList;
private boolean mIsRetransformable;
}
constructor
public class TransformerManager {
TransformerManager(boolean isRetransformable) {
mTransformerList = new TransformerInfo[0];
mIsRetransformable = isRetransformable;
}
}
xxxTransformer
addTransformer
public class TransformerManager {
public synchronized void addTransformer(ClassFileTransformer transformer) {
TransformerInfo[] oldList = mTransformerList;
TransformerInfo[] newList = new TransformerInfo[oldList.length + 1];
System.arraycopy(oldList, 0, newList, 0, oldList.length);
newList[oldList.length] = new TransformerInfo(transformer);
mTransformerList = newList;
}
}
removeTransformer
public class TransformerManager {
public synchronized boolean removeTransformer(ClassFileTransformer transformer) {
boolean found = false;
TransformerInfo[] oldList = mTransformerList;
int oldLength = oldList.length;
int newLength = oldLength - 1;
// look for it in the list, starting at the last added, and remember
// where it was if we found it
int matchingIndex = 0;
for (int x = oldLength - 1; x >= 0; x--) {
if (oldList[x].transformer() == transformer) {
found = true;
matchingIndex = x;
break;
}
}
// make a copy of the array without the matching element
if (found) {
TransformerInfo[] newList = new TransformerInfo[newLength];
// copy up to but not including the match
if (matchingIndex > 0) {
System.arraycopy(oldList, 0, newList, 0, matchingIndex);
}
// if there is anything after the match, copy it as well
if (matchingIndex < (newLength)) {
System.arraycopy(oldList, matchingIndex + 1, newList, matchingIndex, (newLength) - matchingIndex);
}
mTransformerList = newList;
}
return found;
}
}
includesTransformer
public class TransformerManager {
synchronized boolean includesTransformer(ClassFileTransformer transformer) {
for (TransformerInfo info : mTransformerList) {
if (info.transformer() == transformer) {
return true;
}
}
return false;
}
}
transform
public class TransformerManager {
public byte[] transform(ClassLoader loader,
String classname,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) {
boolean someoneTouchedTheBytecode = false;
TransformerInfo[] transformerList = getSnapshotTransformerList();
byte[] bufferToUse = classfileBuffer;
// order matters, gotta run 'em in the order they were added
for (int x = 0; x < transformerList.length; x++) {
TransformerInfo transformerInfo = transformerList[x];
ClassFileTransformer transformer = transformerInfo.transformer();
byte[] transformedBytes = null;
try {
transformedBytes = transformer.transform(loader, classname, classBeingRedefined, protectionDomain, bufferToUse);
} catch (Throwable t) {
// don't let any one transformer mess it up for the others.
// This is where we need to put some logging. What should go here? FIXME
}
if (transformedBytes != null) {
someoneTouchedTheBytecode = true;
bufferToUse = transformedBytes;
}
}
// if someone modified it, return the modified buffer.
// otherwise return null to mean "no transforms occurred"
byte[] result;
if (someoneTouchedTheBytecode) {
result = bufferToUse;
}
else {
result = null;
}
return result;
}
}
总结
本文内容总结如下:
- 第一点,在
InstrumentationImpl
当中,transformer 会根据是否具有 retransform 能力而分开存储。 - 第二点,在
TransformerManager
当中,重点关注transform
方法的处理逻辑。