使用 ByteBuddy 创建一个转换器以从代理添加 class
Creating a transformer to add a class from an agent using ByteBuddy
我正在尝试从使用 ByteBuddy 实现的代理加载 classes。我在代理中定义了一个 class 并想在目标程序中加载它。这是我的变压器的样子:
public class ClassLoaderTransformer implements AgentBuilder.Transformer {
private final Class<?> targetClass;
public ClassLoaderTransformer(Class<?> targetClass) {
this.targetClass = targetClass;
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
try {
final Class<?> aClass = Class.forName(typeDescription.getName());
resolveClassLoadingStrategy(aClass).load(classLoader, singletonMap(
new TypeDescription.ForLoadedType(targetClass),
ClassFileLocator.ForClassLoader.read(targetClass)
));
} catch (Exception e){
System.out.println("Something went terribly wrong: " + e.getMessage());
}
return builder;
}
private static ClassLoadingStrategy<ClassLoader> resolveClassLoadingStrategy(Class<?> targetClass) throws IllegalAccessException {
if ( !ClassInjector.UsingLookup.isAvailable() ) {
return new ClassLoadingStrategy.ForUnsafeInjection(targetClass.getProtectionDomain() );
}
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(targetClass, lookup);
return ClassLoadingStrategy.UsingLookup.of( privateLookup );
}
}
但是,此代码无效。它抛出以下错误:
tech.ikora.seleniumagent.helpers.SourcePageFetcher must be defined in the same package as org.openqa.selenium.remote.RemoteWebDriver
堆栈跟踪如下所示:
java.lang.IllegalArgumentException: tech.ikora.seleniumagent.helpers.SourcePageFetcher must be defined in the same package as org.openqa.selenium.remote.RemoteWebDriver
at net.bytebuddy.dynamic.loading.ClassInjector$UsingLookup.injectRaw(ClassInjector.java:1414)
at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject(ClassInjector.java:110)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$UsingLookup.load(ClassLoadingStrategy.java:492)
at tech.ikora.seleniumagent.ClassLoaderTransformer.transform(ClassLoaderTransformer.java:27)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10364)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10302)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access00(AgentBuilder.java:10068)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$Java9CapableVmDispatcher.run(AgentBuilder.java:10761)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$Java9CapableVmDispatcher.run(AgentBuilder.java:10699)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10258)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$ByteBuddy$ModuleSupport.transform(Unknown Source)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:515)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:423)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:417)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:689)
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:416)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.apache.maven.surefire.booter.IsolatedClassLoader.loadClass(IsolatedClassLoader.java:97)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:515)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:423)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:417)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:689)
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:416)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.apache.maven.surefire.booter.IsolatedClassLoader.loadClass(IsolatedClassLoader.java:97)
at base.BaseTest.setup(BaseTest.java:31)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:132)
at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:61)
at org.testng.internal.ConfigInvoker.invokeConfigurationMethod(ConfigInvoker.java:366)
at org.testng.internal.ConfigInvoker.invokeConfigurations(ConfigInvoker.java:320)
at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:176)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:122)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.testng.TestRunner.privateRun(TestRunner.java:764)
at org.testng.TestRunner.run(TestRunner.java:585)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1218)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
at org.testng.TestNG.runSuites(TestNG.java:1069)
at org.testng.TestNG.run(TestNG.java:1037)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:77)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeMulti(TestNGDirectoryTestSuite.java:159)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:99)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:106)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.plugin.surefire.InPluginVMSurefireStarter.runSuitesInProcess(InPluginVMSurefireStarter.java:80)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:724)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAllProviders(AbstractSurefireMojo.java:682)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:648)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:586)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)
在此示例中,SourcePageFetcher
是目标类,RemoveWebDriver
是 TypeDescription
提供的 class。
此 class 加载程序的目标是加载 classes,这将有助于我创建的一些 Advice
来检测我的代码。我应该尝试以其他方式使用 ClassInjector
吗?还是我以错误的方式看到了问题,或者我应该使用另一个 ClassLoadingStrategy?
如错误消息所示:查找只允许您在指定查找的 class 的包中定义 classes。如果包裹与您的不同:
tech.ikora.seleniumagent.helpers
org.openqa.selenium.remote
JVM 不允许这样做。但是,您也可以从代理使用 UsingUnsafe
策略,因为 Instrumentation
实例可以授予您访问 JVM 内部的权限。否则,您需要将注入挂接到正确包中的 class。
请注意,您可以直接使用 ClassInjector
而不是使用 ClassLoadingStrategy
。
根据@RafaelWinterhalter 的建议,对我有用的解决方案是将 ClassInjector 与 UsingUnsafe 一起使用。这导致以下工作代码:
public class ClassLoaderTransformer implements AgentBuilder.Transformer {
private final Class<?> targetClass;
public ClassLoaderTransformer(Class<?> targetClass) {
this.targetClass = targetClass;
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
try {
ClassInjector.UsingUnsafe.ofBootLoader().inject(singletonMap(
new TypeDescription.ForLoadedType(targetClass),
ClassFileLocator.ForClassLoader.read(targetClass)
));
} catch (Throwable e){
System.out.println("Something went terribly wrong: " + e.getMessage());
}
return builder;
}
}
请注意,在这种情况下,class 正在引导 class 加载程序中加载,因此我们应该尽量让 classes 加载到那里尽可能简单。此外,此处加载的 classes 似乎无法访问子 class 加载器加载的 classes,所以我不得不再次将 classes 保留在承受最小。
我正在尝试从使用 ByteBuddy 实现的代理加载 classes。我在代理中定义了一个 class 并想在目标程序中加载它。这是我的变压器的样子:
public class ClassLoaderTransformer implements AgentBuilder.Transformer {
private final Class<?> targetClass;
public ClassLoaderTransformer(Class<?> targetClass) {
this.targetClass = targetClass;
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
try {
final Class<?> aClass = Class.forName(typeDescription.getName());
resolveClassLoadingStrategy(aClass).load(classLoader, singletonMap(
new TypeDescription.ForLoadedType(targetClass),
ClassFileLocator.ForClassLoader.read(targetClass)
));
} catch (Exception e){
System.out.println("Something went terribly wrong: " + e.getMessage());
}
return builder;
}
private static ClassLoadingStrategy<ClassLoader> resolveClassLoadingStrategy(Class<?> targetClass) throws IllegalAccessException {
if ( !ClassInjector.UsingLookup.isAvailable() ) {
return new ClassLoadingStrategy.ForUnsafeInjection(targetClass.getProtectionDomain() );
}
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(targetClass, lookup);
return ClassLoadingStrategy.UsingLookup.of( privateLookup );
}
}
但是,此代码无效。它抛出以下错误:
tech.ikora.seleniumagent.helpers.SourcePageFetcher must be defined in the same package as org.openqa.selenium.remote.RemoteWebDriver
堆栈跟踪如下所示:
java.lang.IllegalArgumentException: tech.ikora.seleniumagent.helpers.SourcePageFetcher must be defined in the same package as org.openqa.selenium.remote.RemoteWebDriver
at net.bytebuddy.dynamic.loading.ClassInjector$UsingLookup.injectRaw(ClassInjector.java:1414)
at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject(ClassInjector.java:110)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$UsingLookup.load(ClassLoadingStrategy.java:492)
at tech.ikora.seleniumagent.ClassLoaderTransformer.transform(ClassLoaderTransformer.java:27)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10364)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10302)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access00(AgentBuilder.java:10068)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$Java9CapableVmDispatcher.run(AgentBuilder.java:10761)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$Java9CapableVmDispatcher.run(AgentBuilder.java:10699)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10258)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$ByteBuddy$ModuleSupport.transform(Unknown Source)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:515)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:423)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:417)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:689)
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:416)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.apache.maven.surefire.booter.IsolatedClassLoader.loadClass(IsolatedClassLoader.java:97)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:515)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:423)
at java.base/java.net.URLClassLoader.run(URLClassLoader.java:417)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:689)
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:416)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.apache.maven.surefire.booter.IsolatedClassLoader.loadClass(IsolatedClassLoader.java:97)
at base.BaseTest.setup(BaseTest.java:31)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:132)
at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:61)
at org.testng.internal.ConfigInvoker.invokeConfigurationMethod(ConfigInvoker.java:366)
at org.testng.internal.ConfigInvoker.invokeConfigurations(ConfigInvoker.java:320)
at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:176)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:122)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.testng.TestRunner.privateRun(TestRunner.java:764)
at org.testng.TestRunner.run(TestRunner.java:585)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1218)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
at org.testng.TestNG.runSuites(TestNG.java:1069)
at org.testng.TestNG.run(TestNG.java:1037)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:77)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeMulti(TestNGDirectoryTestSuite.java:159)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:99)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:106)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.plugin.surefire.InPluginVMSurefireStarter.runSuitesInProcess(InPluginVMSurefireStarter.java:80)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:724)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAllProviders(AbstractSurefireMojo.java:682)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:648)
at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:586)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)
在此示例中,SourcePageFetcher
是目标类,RemoveWebDriver
是 TypeDescription
提供的 class。
此 class 加载程序的目标是加载 classes,这将有助于我创建的一些 Advice
来检测我的代码。我应该尝试以其他方式使用 ClassInjector
吗?还是我以错误的方式看到了问题,或者我应该使用另一个 ClassLoadingStrategy?
如错误消息所示:查找只允许您在指定查找的 class 的包中定义 classes。如果包裹与您的不同:
tech.ikora.seleniumagent.helpers
org.openqa.selenium.remote
JVM 不允许这样做。但是,您也可以从代理使用 UsingUnsafe
策略,因为 Instrumentation
实例可以授予您访问 JVM 内部的权限。否则,您需要将注入挂接到正确包中的 class。
请注意,您可以直接使用 ClassInjector
而不是使用 ClassLoadingStrategy
。
根据@RafaelWinterhalter 的建议,对我有用的解决方案是将 ClassInjector 与 UsingUnsafe 一起使用。这导致以下工作代码:
public class ClassLoaderTransformer implements AgentBuilder.Transformer {
private final Class<?> targetClass;
public ClassLoaderTransformer(Class<?> targetClass) {
this.targetClass = targetClass;
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
try {
ClassInjector.UsingUnsafe.ofBootLoader().inject(singletonMap(
new TypeDescription.ForLoadedType(targetClass),
ClassFileLocator.ForClassLoader.read(targetClass)
));
} catch (Throwable e){
System.out.println("Something went terribly wrong: " + e.getMessage());
}
return builder;
}
}
请注意,在这种情况下,class 正在引导 class 加载程序中加载,因此我们应该尽量让 classes 加载到那里尽可能简单。此外,此处加载的 classes 似乎无法访问子 class 加载器加载的 classes,所以我不得不再次将 classes 保留在承受最小。