Мне удалось решить проблему с помощью javassist и это руководство о том, как инструментировать код Java.
Как я уже сказал в своем вопросе, проигрывателю YouTube нужен заголовок Referer для воспроизведения некоторых видео (например, музыкальных клипов, принадлежащих VEVO, Sony Music Enternatinment и т. Д.).
Я перехватил prepareConnection из класса URLLoader, который является используется WebEngine JavaFX и вставил мою инструкцию в верхней части тела метода:
c.setRequestProperty("Referer", "https://www.discogs.com");
(Опять же, следуйте руководству для всех инструкции)
(Примечание. Несмотря на то, что в приведенном выше руководстве очень хорошо объясняются концепции, в нем не особо много говорится о роли и структуре файла MANIFEST.MF, поэтому проверьте эту ссылку для получения дополнительной информации об этом аспекте)
Это два моих класса:
MyJavaAgent.java
package com.busytrack.discographymanager.headerfixagent;
import java.lang.instrument.Instrumentation;
public class MyJavaAgent {
public static void premain(String agentArgument, Instrumentation instrumentation) {
ClassTransformer transformer = new ClassTransformer();
instrumentation.addTransformer(transformer);
}
}
ClassTransformer.java
package com.busytrack.discographymanager.headerfixagent;
import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class ClassTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
if (className.equals("com/sun/webkit/network/URLLoader")) {
try {
ClassPool classPool = new ClassPool(true);
CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
CtMethod method = ctClass.getDeclaredMethod("prepareConnection");
String src = "$1.setRequestProperty(\"Referer\", \"https://www.discogs.com\");"; // Confused about there being "$1" instead of "c"? Please read below
method.insertBefore(src);
byteCode = ctClass.toBytecode();
ctClass.detach();
} catch (Exception e) {
e.printStackTrace();
}
}
return byteCode;
}
}
Вот почему я использовал «$ 1» для доступа к параметру метода вместо «c»:
Оператор и блок могут ссылаться на поля и методы. Они также могут ссылаться на параметры метода, в который они вставлены, если этот метод был скомпилирован с параметром -g (для включения атрибута локальной переменной в файл класса). В противном случае они должны получить доступ к параметрам метода через специальные переменные $ 0, $ 1, $ 2, ..., описанные ниже. Доступ к локальным переменным, объявленным в методе, не разрешен, хотя объявление новой локальной переменной в блоке разрешено.
Полное руководство по javassist можно найти здесь.
После упаковки двух классов и файла MANIFEST.MF в отдельный JAR импортируйте его в свою среду IDE (я использовал Eclipse) и добавьте следующий аргумент VM:
-javaagent:./(your-jar-name).jar
В Eclipse вы можете добавить аргументы виртуальной машины следующим образом:
right click on your project -> Run As -> Run Configurations... -> open the Arguments tab -> insert your VM argument -> Apply
Надеюсь, это кому-то поможет. Я знаю, что потратил несколько дней на эту проблему. Я не знаю, лучший ли это подход, но он выполняет свою работу за меня. Тем не менее, это заставляет меня задаться вопросом, почему нет простого способа установки заголовков запросов для JavaFX WebEngine ...
Позднее изменение:
Я нашел гораздо более чистый и более простой подход для загрузки агентов Java, динамически, без необходимости создавать отдельный JAR файл манифеста, импортируя их. , передача параметра виртуальной машины -javaagent при запуске и т. д.
Я использовал ea-agent-loader (ссылка для загрузки JAR ).
Импортируйте JAR в свою среду IDE и измените класс MyJavaAgent (тот, который имеет метод premain) на следующий:
package com.busytrack.discographymanager.headerfixagent;
import java.lang.instrument.Instrumentation;
public class MyJavaAgent {
public static void agentmain(String agentArgument, Instrumentation instrumentation) {
ClassTransformer transformer = new ClassTransformer();
instrumentation.addTransformer(transformer);
}
}
Мой основной метод из MainClass выглядит так:
public static void main(String[] args) {
AgentLoader.loadAgentClass(MyJavaAgent.class.getName(), null); // Load the MyJavaAgent class
launch(args); // Start the JavaFX application
}
Я хотел иметь возможность загружать агент динамически, потому что использование статического метода требовало от меня создания отдельных модулей запуска для всех платформ и передачи параметра -javaagent при запуске. Теперь я могу экспортировать исполняемый JAR из eclipse, как я обычно это делаю, и агент загрузится автоматически (параметры виртуальной машины не требуются). Спасибо, BioWare за этот инструмент!: D
person
Community
schedule
30.04.2016