我通过
使用 javaagent(带有 Javaassit)premain(String agentArgs, Instrumentation inst)
方法,我很好奇为什么 ClassFileTransformer 不考虑类
简短描述:
- 我的项目中有两个类,其中应用了 javaagent (premain)
- MyMainClass 是具有 main 方法的类
- MyLogicReference 类不是通过导入引用的,...在 MyMainClass
- 仅为 MyMainClass 调用 ClassFileTransformer 转换方法,但不为 MyLogicReference 调用
- 如果我调用 java.lang.instrument.Instrumentation getAllLoadedClasses 那么我可以看到 MyLogicReference 类已加载
- <强>?这是代理的工作方式吗?如果是,我该如何让代理也转换第二个(MyLogicReference)类?
更新
我想我在 Javadocs https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/ClassFileTransformer.html 中找到了一些有用的信息.
在 java.lang.instrument.Instrumentation.retransformClasses 中,我应该能够从示例中注册 MyLogicReference 类。但我仍然想知道这种行为...让我们尝试一下...
for each transformer that was added with canRetransform true, the transform method is called in these transformers
详细:
我正在使用代理来更改方法,...通过注释(某种注入(inject))。
我已将类精简为下面的一次,我想知道为什么只有 MyMainClass 被放入 javaagent 转换器(classfilebuffer),而不是 MyLogicReference 类。
public class MyMainClass {
... //Main method and call of myMethod();
@MyAnnotationToApplyLogic
public void myMethod(){
//Some code here
}
我的流程更改代码的入口点是我引用另一个类 (MyLogicReference) 的注释...
@Documented
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.CLASS)
@Functional(value = MyLogicReference.class, type = ElementType.PARAMETER)
public @interface MyAnnotationToApplyLogic {
}
public class MyLogicReference {
// @MyAnnotationToApplyLogic in the MyMainClass method references to this class
// The Javaagent Class file transformer adjust the MyMainClass.myMethod code based on the annotation
public void mySecondMethod(){
}
}
如果我使用
java.lang.instrument.Instrumentation getAllLoadedClasses method
我可以看到 MyLogicReference 类。但此类从未调用过 ClassFileTransformer。这对于 javaagents 来说正确吗?
例如,如果我在 MyMainClass 中导入 MyLogiReference.class,我就会发现调用了变压器。
So my current assumption is that only classes/subclasses which are directly referenced over the main class are send to the ClassFileTransformer. If this is correct than how can I force the javaagent to transform a class which hasn't been transformed before ?
我的 javaaagent list 条目 (MVN):
<Premain-Class>com.MyTestAgent</Premain-Class>
<Agent-Class>com.MyTestAgent</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
我将 ClassFileTransformer 剥离到此,但第二个类仍未加载:
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (!className.startsWith("java/") && !className.startsWith("javax/") && !className.startsWith("sun/")) {
log("NOW PROCESSING: " + className);
return classfileBuffer;
}
return null;
}
//Output:
//NOW PROCESSING: MyMainClass
最佳答案
根据您所说的,我猜测您是指 javaagent 代码中的MyLogicReference。因此,JVM 在检测启动之前加载该类。需要记住两件事:
- Java代理只是一个java程序,它需要加载类。
- Java 代理在加载类时对其进行转换。对于在 java 代理启动之前加载的任何类,您将需要使用 java.lang.instrument.Instrumentation#retransformClasses (正如您自己注意到的那样)。
使用java.lang.instrument.Instrumentation#retransformClasses在这里似乎也没有必要。在我看来,最好避免它(为了简单起见)。您可以:
- 将 javaagent 使用的代码与正在检测的代码分开。
- 仅将 MyLogicReference 作为字符串引用,例如。使用
foo.getClass().getName().equals("MyLogicReference")
而不是foo instanceof MyLogicReference
根据提供的信息,我还想知道您是否考虑使用注释处理器( https://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/Processor.html )。
关于Javaagent 应用程序类未附加到变压器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37308217/