In Apache JMeter, which directory does a third-party plugin JAR go in, and which one takes its dependencies?
answer
- Two directories, two different jobs
- One of them is scanned; one is not
- Dependencies must not sit beside plugins
- Only files ending .jar, no sub-directories
basics
~10 sThe plugin JAR itself goes in JMETER_HOME/lib/ext. The utility and dependency JARs it needs go in JMETER_HOME/lib. Only lib/ext is scanned for new JMeter components, and only files ending in .jar are picked up.
solid answer
~40 sDrop the plugin's own JAR - the one holding the sampler, listener, timer or GUI classes - into `JMETER_HOME/lib/ext`, and every library it depends on into `JMETER_HOME/lib`. JMeter's launcher puts the `.jar` files sitting directly in `lib`, `lib/ext` and `lib/junit` onto the classpath at startup, so all three are *loadable*; the difference is that only `lib/ext` (plus whatever the `search_paths` property adds) is *scanned* for JMeter components, which is how a plugin's elements reach the Add menus. The manual is explicit that `lib/ext` is not for utility or dependency jars. Three details bite: JARs in sub-directories are ignored, files that are not `.jar` are ignored, and setting the `CLASSPATH` environment variable achieves nothing because `bin/jmeter` starts the JVM with `java -jar`. Restart JMeter after adding a JAR.
code
text · 15 linesapache-jmeter-6.0.0/
bin/
jmeter.properties
user.properties
lib/
postgresql-42.7.4.jar <- dependency the plugin needs
cmdrunner-2.3.jar
ext/
ApacheJMeter_core.jar
jmeter-plugins-manager-2.0.jar <- plugin JAR
jmeter-plugins-dummy-0.4.jar <- plugin JAR
mystuff/
ignored.jar <- never loaded: sub-directory
junit/
my-junit-tests.jargo deeper
Remember the pair: the plugin JAR goes in lib/ext, the libraries it needs go in lib, and you restart JMeter afterwards.
Explain that all three shipped directories reach the classpath but only lib/ext is scanned for components, which is why a plugin in lib loads yet never appears in the menus.
Show that you provision lib and lib/ext deliberately - image layer, checked-in directory or install script - because a .jmx names plugin classes and will not open without them.
Own the policy: who may add a JAR to a shared injector, how the contents are versioned and reproduced, and what the scan cost of a bloated lib/ext buys the team.
Apache JMeter 6.0.0 ships no plugin registry, no manifest to edit and no install command in the Apache download. Installing a third-party plugin means putting a JAR file in the right directory and restarting, so getting the directory wrong is the commonest reason a freshly downloaded plugin "does not appear". ## The three directories JMeter reads at startup `NewDriver`, the class `bin/jmeter` actually launches, builds JMeter's classloader before any other JMeter code runs. It looks in exactly three places under `JMETER_HOME`: - **`lib`** - utility and dependency JARs: JDBC drivers, messaging client libraries, and every library a plugin needs but does not bundle inside itself. - **`lib/ext`** - JMeter components and plugins: the JAR that contains samplers, listeners, timers, controllers, assertions, config elements and their GUI classes. - **`lib/junit`** - JARs holding the JUnit `TestCase` classes that the JUnit Request sampler drives. Every `.jar` found **directly** in those directories is added, sorted by name so the order is predictable across machines. Sub-directories are not walked, and anything that is not a `.jar` is skipped without comment - the manual notes that JMeter will only find `.jar` files, not `.zip`. ## Loadable is not the same as discoverable Because all three directories land on the classpath, a plugin JAR technically *loads* from any of them. What makes `lib/ext` special is discovery. `JMeterUtils.getSearchPaths()` returns `JMETER_HOME/lib/ext` first, followed by whatever the `search_paths` property adds, and that array is the search path JMeter's class finder walks when it builds the list of components it is able to offer. A component JAR dropped into `lib` sits on the classpath and can still be named explicitly, but nothing scans it, so its elements never appear in the tree's Add menus. The reverse mistake costs you as well. The manual says plainly that you should not use `lib/ext` for utility jars or dependency jars used by the plugins, because it is only intended for JMeter components and plugins. Piling a plugin's transitive dependencies into `lib/ext` turns every one of them into a candidate for the component scan on every startup: pure cost, no benefit. | Directory | What belongs there | On the classpath | Scanned for components | |---|---|---|---| | `lib` | utility and dependency JARs | yes | no | | `lib/ext` | plugin and component JARs | yes | yes | | `lib/junit` | JUnit `TestCase` JARs | yes | by the JUnit Request class chooser | ## The rules that trip people up 1. **`CLASSPATH` does nothing.** JMeter is started with `java -jar`, and the `java` command silently ignores both the `CLASSPATH` environment variable and the `-classpath`/`-cp` options when `-jar` is used. This is a Java rule, not a JMeter quirk, and the manual calls it out for exactly that reason. 2. **A restart is required.** The classloader is built and the component scan runs once, during startup. Copying a JAR into `lib/ext` while JMeter is open changes nothing until you relaunch it. 3. **Only `.jar`.** A directory of loose `.class` files, or a `.zip`, is invisible to the launcher. 4. **No recursion.** `lib/ext/mystuff/plugin.jar` is not found; `lib/ext/plugin.jar` is. 5. **A missing dependency reads like a broken plugin.** The plugin's element may appear in the menu, then fail with a `NoClassDefFoundError` the moment it runs, because its library never made it into `lib`. ## When you cannot write into the installation A locked-down or shared JMeter installation is common, and three properties in `bin/jmeter.properties` exist for it: `search_paths` adds directories to the component search path alongside `lib/ext`, while `user.classpath` and `plugin_dependency_paths` add directories of dependency JARs alongside `lib`. All three are shipped commented out, so none of them is set unless you set it. ## Why this outlives the first install An injector's `lib/ext` is part of a test plan's contract, not a local convenience. A `.jmx` records the fully qualified class name of every element it uses, so a plan authored on a workstation that has a plugin installed is unopenable on a machine that does not. Treat the contents of `lib` and `lib/ext` as something you provision deliberately - a container image layer, a checked-in directory, or a scripted install step - rather than something a person copies once and forgets.
- What is JMETER_HOME/lib/junit for, and how does it differ from lib/ext?It is where the JUnit Request sampler expects the JARs holding your JUnit test classes. Its class chooser scans `lib/junit` plus any directories named by the `user.classpath` property for classes extending JUnit's `TestCase`, whereas `lib/ext` is scanned for JMeter's own component types such as samplers and listeners.
- Why does exporting CLASSPATH before running bin/jmeter not make a plugin visible?Because `bin/jmeter` launches the JVM with `java -jar`, and `java` silently ignores the `CLASSPATH` environment variable and the `-classpath`/`-cp` options whenever `-jar` is used. Put the JAR in `lib` or `lib/ext`, or point the `user.classpath` or `search_paths` property at the directory holding it.
saying these in an interview costs you the question
- Says exporting CLASSPATH makes JMeter find the plugin JAR
- Puts a plugin's dependency jars into lib/ext beside the plugin
- Expects JMeter to recurse into sub-directories of lib/ext
- Thinks a zip of classes in lib/ext will be loaded
- Assumes a new jar is picked up without restarting JMeter