gpt4 book ai didi

Java:在方法调用之前和之后注入(inject)代码

转载 作者:行者123 更新时间:2023-12-04 04:18:23 28 4
gpt4 key购买 nike

我冒这个问题的风险知道很多其他问题 have been asked以某种方式触及相同的问题。但它们要么很旧,要么非常具体,要么难以理解,而且答案也非常具体,似乎不适用于我的用例。

我想要实现的目标描述起来很简单,就是在 Java 中的方法调用前后注入(inject)代码。这是一个简单的例子。我想要类似这行代码的东西:

method(p1, @ANNOTATION(type=String) p2, p3);

脱糖

Wrapper<String> w = new Wrapper<>(p2);
method(p1, w, p3);
p2 = w.get();

在更大的语句 block 的上下文中,使用预定义的 Wrapper 类。我对用于编译代码的构建环境的控制有限,因此任何解决方案都应该可以通过 Gradle 插件/依赖项实现。

到目前为止我看过的内容(没有深入了解其中的任何一个):

  • Java Annotations:在回答类似问题时从未认真考虑过,所以我猜他们无法实现这一点
  • Aspect 框架,如 AspectJ 或 Spring Aspects:最常被提及,但它们似乎只能包装整个方法,而不是它们的特定调用
  • 字节码操作框架,如 asm 或 cglib:似乎通常能够做到这一点,但它们非常重量级并且需要一些管道,尤其是。在构建方面,实现它

那么,有什么解决方案呢?

最佳答案

您可以使用 aspectj 来实现您想要的。假设我们有一个编译后的 jar,其方法类似于您所描述的:您想要拦截从应用程序中的特定位置 (-s) 发出的对 logStuff 方法的调用,并更改逻辑以将参数包装在 DummyContainer 对象中。您的代码可能如下所示。



@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public static @interface DummyAnnotation {
Class type();
}

//that is your target method
public static void logStuff(@DummyAnnotation(type = String.class) Object data) {
if(data instanceof String) {
System.out.println("String: " + data);
} else {
System.out.println("Not a string " + data);
}
}

虚拟容器类:



public static class DummyContainer {
private String string;
private Class clazz;

public DummyContainer(String string, Class clazz) {
this.clazz = clazz;
this.string = string;
}
@Override
public String toString() {
return "DummyContainer=[clazz: " + clazz + ", string: " + string + "]";
}
}

看点:



@Aspect
public class WrapperAspect {

@Pointcut("call(* "
/**method to intercept*/
+ "com.yourpackage.YourType.logStuff(Object)) && args(param) && "
/**only calls made from within that location
* will be intercepted. Remove it to intercept
* calls from everywhere*/
+ "within(test.Runner)")
public void logStuffPointcut(Object param) {}


@Around("logStuffPointcut(param)")
public void simpleWrap(Object param, ProceedingJoinPoint jp) throws Throwable {
String calledMethodName = jp.getSignature().getName();
Class type = jp.getSignature().getDeclaringType();
Method method = type.getDeclaredMethod(calledMethodName, Object.class);
DummyAnnotation annotation = method.getParameters()[0].getAnnotation(DummyAnnotation.class);
DummyContainer wrapped = new DummyContainer((String) param, (Class)annotation.type());
//code before method call
jp.proceed(new Object[] {wrapped});
//code after method call
}
}

test.Runner 类中调用 logStuff 的方法



public static void main(String[] args) {
Object instance = "thats a string";
System.out.println("Obj type : " + instance.getClass());
YourType.logStuff(instance);
System.out.println("Obj type : " + instance.getClass());
}

输出:

Obj type : class java.lang.StringNot a string DummyContainer=[clazz: class java.lang.String, string: thats a string]Obj type : class java.lang.String

为了构建项目,我使用 Maven。以下是我的 pom.xml 的构建部分的样子:

    ...    ...        <build>            <plugins>                <plugin>                    <groupId>org.apache.maven.plugins</groupId>                    <artifactId>maven-compiler-plugin</artifactId>                    <version>3.6.2</version>                    <configuration>                        <source>1.8</source>                        <target>1.8</target>                    </configuration>                </plugin>                <plugin>                    <groupId>org.codehaus.mojo</groupId>                    <artifactId>aspectj-maven-plugin</artifactId>                    <version>1.11</version>                    <dependencies>                        <dependency>                            <groupId>org.aspectj</groupId>                            <artifactId>aspectjrt</artifactId>                            <version>1.8.13</version>                        </dependency>                        <dependency>                            <groupId>org.aspectj</groupId>                            <artifactId>aspectjtools</artifactId>                            <version>1.8.13</version>                        </dependency>                    </dependencies>                    <configuration>                        <Xajruntimetarget>1.8</Xajruntimetarget>                        <complianceLevel>1.8</complianceLevel>                        <weaveDependencies>                            <weaveDependency>                                <groupId>your.jar.group.id</groupId>                                <artifactId>artifactid</artifactId>                            </weaveDependency>                        </weaveDependencies>                    </configuration>                    <executions>                        <execution>                            <goals>                                <goal>compile</goal>                            </goals>                        </execution>                    </executions>                </plugin>            </plugins>        </build>    ...    ...

关于Java:在方法调用之前和之后注入(inject)代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60007441/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com