如何实现JShell实例与JVM动态加载类的共享?两类执行控件差异
Hey there! Let's tackle this problem head-on—first I'll clarify the difference between DirectExecutionControl and LocalExecutionControl, then walk you through exactly how to make your dynamically loaded classes accessible in JShell.
The key distinction boils down to process isolation:
DirectExecutionControl: Runs all JShell-evaluated code directly in the same JVM process as your application. It shares the same classloaders and memory space as your main code. There's no isolation here—so if your dynamic classes are in a classloader that's visible to the JShell instance, they should theoretically be accessible.LocalExecutionControl: Spawns a separate local process to run JShell code. This adds isolation (great for safety if you're evaluating untrusted code), but it means the separate process has its own classpath and classloaders. Your main JVM's dynamically loaded classes aren't automatically shared with this process, which is why you saw the same issue when switching to it.
Here's the step-by-step fix to get those runtime-loaded classes working in JShell:
Pass your dynamic classloader to JShell's execution engine
JShell's default setup uses its own classloader, which won't see classes loaded by your custom runtime classloader. To fix this, initialize JShell withDirectExecutionControland explicitly pass in the classloader that loaded your dynamic classes.Example code:
// Assume 'myDynamicClassLoader' is the ClassLoader instance that loaded your runtime classes JShell.Builder jshellBuilder = JShell.builder(); // Include your existing application classpath to keep compile-time classes accessible jshellBuilder.classpath(System.getProperty("java.class.path")); // Use DirectExecutionControl with your custom classloader jshellBuilder.executionEngine(new DirectExecutionControl(myDynamicClassLoader)); JShell jshell = jshellBuilder.build();This ensures JShell uses the same classloader that has your dynamically loaded classes.
Explicitly reference the dynamic class
Even with the right classloader, JShell might not auto-discover the dynamic class. You can either import it using its fully qualified name, or reference it directly:// In JShell: import com.yourcompany.yourmodule.YourDynamicClass; // Or use the full name without importing: var dynamicInstance = new com.yourcompany.yourmodule.YourDynamicClass();Validate class visibility
If you're still having trouble, double-check that your dynamic class is actually present in the classloader you're using. Add this quick check before initializing JShell:try { Class<?> loadedClass = myDynamicClassLoader.loadClass("com.yourcompany.yourmodule.YourDynamicClass"); System.out.println("Confirmed class is loaded: " + loadedClass.getName()); } catch (ClassNotFoundException e) { System.err.println("Dynamic class not found in the classloader!"); e.printStackTrace(); }This will confirm if the issue is with classloader visibility or something else.
Stick with DirectExecutionControl for this use case
SinceLocalExecutionControlruns in a separate process, it can't access classloaders from your main JVM. If your dynamic classes are only loaded in the main process,LocalExecutionControlwill never be able to see them—soDirectExecutionControlis the right choice here.
内容的提问来源于stack exchange,提问作者Joba

