gpt4 book ai didi

java - 添加代码打包私有(private)库方法

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:54:57 26 4
gpt4 key购买 nike

我有一个包含包私有(private)方法的库类。不能通过子类直接覆盖此方法。当从库内部调用这个包私有(private)方法时,有没有办法,无论多么丑陋,都可以执行自己的代码,例如使用 AspectJ?

这是该类的一个简化示例(packagePrivateMethod() 实际上不是直接调用的,而是从 native 代码调用的):

public LibClass {

public LibClass() {
...
packagePrivateMethod();
...
}

void packagePrivateMethod() {
// <-- here I want to execute additional code
...
}
}

最佳答案

您可以使用相当重量级的方法。

  1. 编写一个小型 Java 代理 SO post about that topic .
  2. 使用提供的 Instrumentation interface拦截类加载
  3. 使用字节码修改库(例如 ASMJava Assist(仅限 Java 6!))来检测字节码(例如,用您真正想做的任何事情替换方法调用。

这会起作用,因为您可以修改所有内容的字节码,但它要求您在执行之前修改该字节码。

当然,您也可以静态地执行此操作,只需修改类文件,将现有的字节代码替换为您在上面的第 3 步中创建的字节代码。

如果您不想/不能静态替换类的字节码,则必须在运行时修改字节码。因为使用 Java 代理是一个好主意。

由于到目前为止这一切都相当抽象,我添加了一个示例,它将拦截您的库类的加载,在包私有(private)方法中注入(inject)方法调用。当 main 方法执行时,您可以从输出中看到,注入(inject)的方法直接在库类代码之前被调用。如果您添加 return; 作为注入(inject)代码,您还可以完全阻止该方法的执行。

下面是使用 Java 6 和 JavaAssist 解决问题的示例代码。如果你想沿着这条路走下去并使用更新的东西,比如 Java 7,你只需要用 ASM 替换字节码操作。这有点不太可读,但也不完全是火箭科学。

主类:

package com.aop.example;

public class Main {

public static void main(String[] args) {
System.out.println("Main starts!");
LibClass libClass = new LibClass();
System.out.println("Main finished!");
}
}

你的库类:

package com.aop.example;

public class LibClass {

public LibClass() {
packagePrivateMethod();
}

void packagePrivateMethod() {
// <-- here I want to execute additional code
System.out.println("In packagePrivateMethod");
}
}

代理:

package com.aop.agent;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;

public class Agent {

public static void premain(String agentArgs, Instrumentation instr) {
System.out.println("Agent starts!");
instr.addTransformer(new ClassFileTransformer() {

@Override
public byte[] transform(ClassLoader classLoader, String className, Class<?> arg2, ProtectionDomain arg3,
byte[] bytes)
throws IllegalClassFormatException {
System.out.println("Before loading class " + className);

final String TARGET_CLASS = "com/aop/example/LibClass";

if (!className.equals(TARGET_CLASS)) {
return null;
}

LoaderClassPath path = new LoaderClassPath(classLoader);
ClassPool pool = new ClassPool();
pool.appendSystemPath();
pool.appendClassPath(path);

try {
CtClass targetClass = pool.get(TARGET_CLASS.replace('/', '.'));
System.out.println("Enhancing class " + targetClass.getName());
CtMethod[] methods = targetClass.getDeclaredMethods();
for (CtMethod method : methods) {
if (!method.getName().contains("packagePrivateMethod")) {
continue;
}
System.out.println("Enhancing method " + method.getSignature());
String myMethodInvocation = "com.aop.agent.Agent.myMethodInvocation();";
method.insertBefore(myMethodInvocation);
}
System.out.println("Enhanced bytecode");

return targetClass.toBytecode();
}
catch (CannotCompileException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
catch (NotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

});
}

public static void myMethodInvocation() {
System.out.println("<<<My injected code>>>!");
}
}

运行示例的命令(您必须将代理放入具有属性 Premain-Class: com.aop.agent.Agent 的 list 的 jar 中:

%JAVA_HOME%\bin\java -cp .;..\javassist-3.12.1.GA.jar -javaagent:..\..\agent.jar com.aop.example.Main

此示例运行如下命令的输出:

Agent starts!
Before loading class com/aop/example/Main
Main starts!
Before loading class com/aop/example/LibClass
Enhancing class com.aop.example.LibClass
Enhancing method ()V
Enhanced bytecode
<<<My injected code>>>!
In packagePrivateMethod
Main finished!
Before loading class java/lang/Shutdown
Before loading class java/lang/Shutdown$Lock

关于java - 添加代码打包私有(private)库方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20161210/

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