我希望创建一个代理以附加到我们的实时Tomcat和Weblogic服务器,该代理将拦截对我的公司程序包中声明的所有类的所有方法调用,并记录一些指标,例如执行时间。
我遇到了Byte Buddy库,它似乎可以满足此需求。但是,对于使用Byte Buddy创建代理的方法,我还不是100%清楚:
byte-buddy-agent:http : //mydailyjava.blogspot.ie/2015/01/make-agents-not-frameworks.htmlbyte-buddy-agent所以不确定我是否打算使用它。
https://github.com/raphw/byte-buddy/tree/master/byte-buddy-agent我采用了创建自己的代理的方法,并使用Maven对其进行了打包,以将Byte Buddy作为胖子(这样Byte Buddy代码在类路径中)包括进了我的引用catalina.bat。
编辑:自从我下载了源代码,并发现AgentBuilder依赖于byte-buddy-agent包,因此上述问题无关紧要。
Tomcat可以正常启动,并且可以看到代理被调用,就像看到的“ Entered premain”一样System.out。
但是,System.out当我在部署到Tomcat的单独war文件上执行代码时,从未看到“已拦截” 。
编辑:以下代码根据拉斐尔的回应进行了更新,现在可以正常工作。
有人可以告诉我在这里我可能做错了什么吗?我已经在下面包含了代理代码。
另外,有人可以告诉我哪个ElementMatchers最适合软件包匹配吗?我尝试过,nameStartsWith但是没有任何效果,API文档也没有说明它是否是完全限定的类名。
*编辑:nameStartsWith会检查软件包。*
无论如何,在此先感谢您的帮助!
package com.mycompany.agent;
import java.lang.instrument.Instrumentation;
import java.util.concurrent.Callable;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
public class MyAgent {
public static void premain(String agentArgument, Instrumentation instrumentation) {
System.out.println("Entered premain");
try{
new AgentBuilder.Default()
.withListener( new AgentBuilder.Listener() …Run Code Online (Sandbox Code Playgroud) 我正在尝试在Android中使用Byte Buddy库但我收到错误:
java.lang.IllegalStateException:此JVM的版本字符串似乎无效:0
我还没有编码,只是:
ByteBuddy test = new ByteBuddy();
Run Code Online (Sandbox Code Playgroud)
在我的App.java中
我已导入:
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>0.7.7</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
但它没有用,我尝试过:
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-android</artifactId>
<version>0.7.7</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
但我仍然得到同样的错误.
编辑
在初始化ByteBuddy之前我已经把这行放了:
System.setProperty("java.version", "1.7.0_51");
Run Code Online (Sandbox Code Playgroud)
但现在我又得到了另一个错误:
引起:java.lang.UnsupportedOperationException:无法加载此类类文件.
对于此代码:
Class<?> dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V6)
.subclass(Object.class)
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello World!"))
.make()
.load(getClass().getClassLoader(), AndroidClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
Run Code Online (Sandbox Code Playgroud) 当使用 拦截方法的实现时@Advice,是否可以访问局部变量?
我有一个类,例如:
public class Sample{
private String a;
private String b;
public Sample(String a, String b)
{
this.a = a;
this.b = b;
}
public String getA() {return a;}
public String getB() {return b;}
}
Run Code Online (Sandbox Code Playgroud)
我想创建一个从 Sample 类继承的动态类,并向其中添加字段(字符串字段)。
我试图做:
DynamicType.Builder<? extends Sample> classBuilder = new ByteBuddy()
.subclass(Sample.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.name("sampleSon");
classBuilder.defineConstructor(Visibility.PUBLIC)
.withParameters(String.class, String.class, String.class)
.intercept(MethodCall.invoke(Sample.class.getConstructor(String.class, String.class))
.withArgument(0, 1)
.andThen(FieldAccessor.ofField("c").setsArgumentAt(2)));
Run Code Online (Sandbox Code Playgroud)
但是当我尝试从这个类创建一个实例时:
Class<? extends Sample> newSampleClass= classBuilder.make().load(ClassLoader.getSystemClassLoader()).getLoaded();
Sample sample = newSampleClass.getConstructor(String.class, String.class, String.class).newInstance("a", "b", "c");
Run Code Online (Sandbox Code Playgroud)
它抛出一个异常:
public class Sample{
private String a;
private String …Run Code Online (Sandbox Code Playgroud) 使用 Byte Buddy 的建议 API,是否可以从检测方法返回而不实际执行它?
一种用例是实现缓存并返回缓存值(如果存在),而不是再次计算该值。
@Advice.OnMethodEnter
public static Object returnCachedValue(@Advice.Argument(0) String query) {
if (cache.containsKey(query)) {
// should "abort" method call
return cache.get(query);
}
}
Run Code Online (Sandbox Code Playgroud)
我知道上面的这个代码示例只是创建了一个我可以在@Advice.OnMethodExit方法中获取的局部变量。但是有没有办法中止对显式的方法调用return?如果是,这也适用于void方法吗?
我整夜都在寻找,似乎在任何地方都找不到解决方案。每次我尝试从我的应用程序登录数据库时,我都会得到以下信息:
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774) ~[jfxrt.jar:?]
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657) ~[jfxrt.jar:?]
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) ~[jfxrt.jar:?]
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) ~[jfxrt.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[jfxrt.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[jfxrt.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) ~[jfxrt.jar:?]
at javafx.event.Event.fireEvent(Event.java:198) ~[jfxrt.jar:?]
at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3470) ~[jfxrt.jar:?]
at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3398) ~[jfxrt.jar:?]
at javafx.scene.Scene$MouseHandler.process(Scene.java:3766) ~[jfxrt.jar:?]
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) ~[jfxrt.jar:?]
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) ~[jfxrt.jar:?]
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) ~[jfxrt.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394) ~[jfxrt.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295) ~[jfxrt.jar:?]
at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_181]
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:432) ~[jfxrt.jar:?]
at …Run Code Online (Sandbox Code Playgroud) 几天来,我一直在寻找“如何在运行时向方法添加注释”的答案,并找到了这个名为 Byte Buddy 的很棒的工具,使用了它,但仍然无法按我的需要工作。我确定它必须能够从这个问题Can Byte Buddy create fields and method annotations at runtime?
有这个类:
public class ClassThatNeedsToBeAnnotated {
public void method(int arg1, String arg2) {
// code that we don't want to touch at all, leave it as is
System.out.println("Called method with arguments " + arg1 + " " + arg2);
}
public void method() {
System.out.println("Called method without arguments");
}
}
Run Code Online (Sandbox Code Playgroud)
和这个代码:
public class MainClass {
public static void main(String[] args) {
ByteBuddyAgent.install();
AnnotationDescription description = AnnotationDescription.Builder.ofType(MyClassAnnotation.class)
.define("value", …Run Code Online (Sandbox Code Playgroud) 我想使用字节伙伴生成一个包含字段的枚举,其中每个枚举常量将不同的参数传递给构造函数。
public enum MyEnum {
private final String blah;
A("foo")
B("bar");
private MyEnum(String blah) {
this.blah = blah;
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试了这个:
new ByteBuddy()
.makeEnumeration("A", "B")
.name("com.foo.MyEnum")
.defineField("blah", String.class, Modifier.FINAL | Modifier.PRIVATE)
.defineConstructor(Visibility.PRIVATE)
.withParameters(String.class)
.intercept(
FieldAccessor.ofField("blah").setsArgumentAt(0)
)
.make()
Run Code Online (Sandbox Code Playgroud)
生成此文件(反编译)。具有相同签名的两个构造函数有些古怪,但无论如何。
public enum MyEnum {
private final String blah;
A,
B;
private MyEnum() {
}
private MyEnum() {
this.blah = var1;
}
}
Run Code Online (Sandbox Code Playgroud)
我看不到将每个枚举常量与一组构造函数参数关联的方法。该makeEnumeration方法只有两个签名,两个签名都使用字符串集合。
字节好友有可能吗?
我有一个 Spring Web 应用程序,可以在 \xe2\x80\x9cspecial\xe2\x80\x9d 模式下运行,其中使用 mockito 来监视某些对象。其中一些对象是最终的(protobuf 消息)。我知道,这可能听起来像是一个坏主意,但可以说它\xe2\x80\x99s 是一个实验。启用mock-maker-inline扩展时,可以在 I\xe2\x80\x99m 上监视最终对象,遇到似乎与字节伙伴和加载一些本机库相关的问题。当不使用扩展(并且不监视最终类)时,一切都会按预期工作。下面是截断的堆栈跟踪。
java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMaker (alternate: null)\n\xe2\x80\xa6\nCaused by: java.lang.IllegalStateException: Failed to load interface org.mockito.plugins.MockMaker implementation declared in sun.misc.CompoundEnumeration@60cc2b75\n\xe2\x80\xa6\nCaused by: java.lang.reflect.InvocationTargetException\n\xe2\x80\xa6\nCaused by: org.mockito.exceptions.base.MockitoInitializationException:\nCould not initialize inline Byte Buddy mock maker.\n\nIt appears as if your JDK does not supply a working agent attachment mechanism.\nJava : 1.8\nJVM vendor name : AdoptOpenJDK\nJVM vendor version : 25.265-b01\nJVM name : OpenJDK 64-Bit Server VM\nJVM version : 1.8.0_265-b01\nJVM info : …Run Code Online (Sandbox Code Playgroud) 我有一个Implementation由Advice#wrap(Implementation), 和 a的返回值产生的结果FixedValue。我需要把这些变成一个单一的Implementation不会导致字节码验证错误。
那是:
Implementation advisedMethodCall = Advice.to(...).wrap(someMethodCall);
Implementation firstArgument = FixedValue.argument(0);
// How can I "run" advisedMethodCall followed by firstArgument?
Run Code Online (Sandbox Code Playgroud)
更一般地说:我如何取两个Implementations(不是 的实例Implementation.Composable)并组合它们?
(我从之前的实验中知道,MethodCall通过某种名为 的内部类来实现这一点TerminationHandler,其中所讨论的特定实现TerminationHandler.Simple.DROPPING对堆栈执行某些操作以允许您组合MethodCalls。我不知道如何做与Implementationthat类似的事情不是MethodCall(例如,由 产生的Advice#wrap(Implementation))。)