长话短说:
完整故事:我创建了一个代理,以便在加载到我的项目中的每个类中注入一些自定义代码。我使用选项-javaagent在运行时添加这个代理,这个工作很好。
的问题是,当我的代理附加到JVM时,已经加载了很多类(例如java.io.*类),所以我的转换错过了一整组类。因此,我的问题是:有一种方法,我可以用仪器,所有的课程,我错过了?所有建议都是受欢迎的。。
现在我已经试过这样做了:
public class MyTransformer implements ClassFileTransformer {
public static void premain(String agentArgs, Instrumentation inst) {
final MyTransformer t = MyTransformer .getInstance();
inst.addTransformer(t, true);
MyTransformer .log.info(t + " registered via JVM option -javaagent");
// TEST
// by the time we are attached, the classes to be
// dumped may have been loaded already. So, check
// for candidates in the loaded classes.
Class[] classes = inst.getAllLoadedClasses();
List<Class> candidates = new ArrayList<Class>();
for (Class c : classes) {
if (inst.isModifiableClass(c) && inst.isRetransformClassesSupported()){
candidates.add(c);
}
}
System.out.println("There are "+candidates.size()+" classes");
try {
// if we have matching candidates, then
// retransform those classes so that we
// will get callback to transform.
if (! candidates.isEmpty()) {
Iterator it = candidates.iterator();
while(it.hasNext()){
Class c = (Class)it.next();
if(!c.getName().startsWith("javassist")){
System.out.println(" ========================> In Progress:"+c.getName());
inst.retransformClasses(c);
}
}
}else{
System.out.println("candidates.isEmpty()");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
final String dot_classname = className.replace('/', '.');
// log classes that are going throug the instrumentor
// just log if the java.io. is coming here
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(path, true)));
out.println(dot_classname);
out.close();
} catch (IOException ex) {
Logger.getLogger(MyTransformer.class.getName()).log(Level.SEVERE, null, ex);
}
return byteCode;
}
}因此,我的第一次尝试是接受每个已经加载的"premain“方法,如果可能的话,可以使用”reTransfrom“方法"retransfromClasses”。
现在,在我的transform方法中,我只有一个日志,它将将要转换的每个类写入一个文件中。现在我的测试结果是:
There are 1486 classes
==> In Progress:com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser
==> In Progress:java.lang.Enum
==> In Progress:java.lang.ThreadGroup
==> In Progress:java.nio.file.FileSystem
==> In Progress:java.util.regex.Pattern$Prolog
==> In Progress:com.sun.org.apache.xerces.internal.dom.AttributeMap
==> In Progress:java.util.regex.Matcher
==> In Progress:org.apache.commons.beanutils.converters.ShortConverter
==> In Progress:com.google.gson.JsonNull
==> In Progress:java.util.concurrent.CopyOnWriteArrayList$COWIterator
==> In Progress:java.util.concurrent.locks.ReentrantLock
==> In Progress:java.lang.NoSuchMethodError
==> In Progress:org.apache.commons.lang.BooleanUtils
==> In Progress:java.lang.reflect.WeakCache$CacheValue
==> In Progress:com.google.gson.internal.bind.TypeAdapters$33
==> In Progress:java.lang.reflect.Type
==> In Progress:sun.reflect.generics.scope.AbstractScope
==> In Progress:org.apache.log4j.helpers.DateTimeDateFormat
==> In Progress:sun.nio.cs.MS1252
==> In Progress:java.lang.Integer$IntegerCache
==> In Progress:com.sun.org.apache.xerces.internal.utils.SecuritySupport$3
==> In Progress:org.apache.commons.configuration.MapConfiguration
==> In Progress:org.apache.commons.beanutils.IntrospectionContext
==> In Progress:java.io.Reader
==> In Progress:java.util.WeakHashMap$Holder
==> In Progress:java.util.ServiceLoader$LazyIterator
==> In Progress:java.util.regex.Pattern$Branch
==> In Progress:java.lang.IllegalMonitorStateException
==> In Progress:java.util.regex.Pattern$Curly
==> In Progress:org.apache.commons.configuration.resolver.EntityRegistry
==> In Progress:java.io.IOException
==> In Progress:java.io.FilterOutputStream
==> In Progress:org.apache.log4j.LogManager
==> In Progress:sun.util.logging.PlatformLogger$Level
==> In Progress:java.nio.charset.CoderResult$1
==> In Progress:com.google.gson.FieldNamingPolicy$5
==> In Progress:com.google.gson.internal.ObjectConstructor
==> In Progress:sun.util.calendar.BaseCalendar$Date因此,您可以注意到,我可以找到我感兴趣的每个类(甚至是java.io)。现在,如果我们查看应该包含MyTransformer试图转换的每个类的文件,我们会注意到没有公共条目,这真的很奇怪。
org.apache.commons.beanutils.converters.ShortConverter
com.google.gson.JsonNull
org.apache.commons.lang.BooleanUtils
com.google.gson.internal.bind.TypeAdapters$33
org.apache.log4j.helpers.DateTimeDateFormat
org.apache.commons.configuration.MapConfiguration
org.apache.commons.beanutils.IntrospectionContext
org.apache.commons.configuration.resolver.EntityRegistry
org.apache.log4j.LogManager
com.google.gson.FieldNamingPolicy$5
com.google.gson.internal.ObjectConstructor
org.apache.log4j.Layout
com.google.gson.internal.bind.TypeAdapters
org.apache.log4j.PropertyConfigurator
com.sap.psr.vulas.java.JavaEnumId
org.apache.commons.collections.collection.AbstractSerializableCollectionDecorator
org.apache.commons.logging.impl.LogFactoryImpl
org.apache.commons.lang.text.StrTokenizer我发现的另一个问题是,如果我试图插入Mytransformer.transform(..)方法对字节码进行一些篡改,它将破坏我的执行。我的意思是,我使用的转换操作非常好,因为我在我的代理附加后加载的每个类上都使用它。但不知何故,如果我尝试使用它--那些“重新转换的”类,我会出现这样的错误:
==> In Progress:org.apache.commons.lang.text.StrMatcher$TrimMatcher java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)我知道本机类的转换是有局限性的,但我并不认为我的转换操作试图更改模式。我将调查这一点,并发布最新消息。
发布于 2016-04-24 07:46:41
这个链接类似于您所问的问题。看起来您可以修改本机方法的主体,但不能添加方法或字段。
我可以从您的代码中看到,您正在使用Javassist来完成这个任务。我花了好几个月努力让它开始工作,但它对我不起作用,所以我使用了ASM (顺便说一句)。
那你是怎么做的?首先,我将使用附加API来连接到rt.jar (因为它已经加载了,所以您需要将代理附加到java进程。然后,您可以从agentmain方法将转换器添加到java代理中。然后为要编辑的类创建一个类读取器,并接受扩展的ClassVisitor。然后,重写一个方法,如果它是您想要的方法,则将代码替换为其他代码。您可以看到一个示例在我的吉萨上。您将需要每次转换它,因为它加载到内存-您不需要担心删除代码。
我希望这能帮到你!如有任何问题,请评论:)
发布于 2016-05-11 09:45:25
您是否在代理jar manifest.mf中添加了必需的清单条目?
你的“manifest.mf”看起来怎么样?它应该有类似的东西
Can-Redefine-Classes: true
Can-Retransform-Classes: true
致以敬意,
葛泽西克
https://stackoverflow.com/questions/36790578
复制相似问题