Chapter 32Lesson 01~190 minutes

Plugins, Custom Components, JMeter APIs, and Extension Strategy: Core Concepts and Mental Model

Chapter 31 treated JMX, plugins and test data as security/trust boundaries. Chapter 32 asks what happens when core JMeter is not enough. Extensions can add a sampler, function, listener, visualizer or authoring helper—but every added JAR also adds executable code, classpath state, lifecycle assumptions, thread-safety risk and upgrade coupling. The correct question is not “can I install a plugin?” but “what is the smallest governed extension that solves this problem?”

Core vs pluginCustom JavaClasspathLifecycleSupply chain

Learning objectives

  • Separate Apache JMeter distribution components, third-party plugins, custom Java and utility dependencies.
  • Explain how lib/ext, lib, search_paths, user.classpath and JMX references interact.
  • Understand JavaSamplerClient and Function lifecycle/thread-safety differences.
  • Inspect extension provenance/compatibility before changing classpath.
  • Treat JMX compatibility as a software dependency contract.

1. The practical problem: “install this JAR” is not a design

A team receives a JMX that references a custom sampler. It works on one laptop, fails in CI with ClassNotFoundException, and produces different behavior on one remote engine. Another engineer “fixes” the issue by copying several unpinned JARs into lib/ext. Now the plan's behavior depends on undocumented classpath order. This is a software supply-chain problem inside a load generator.

Mandatory lab boundary: Apache JMeter5.6.3/Java17, no third-party plugin, custom source shown in the lessons, target only 127.0.0.1:8032, 2 threads ×5 loops, 10 HTTP target requests and 20 JTL samples maximum. No production/public target, credential, RMI engine, container registry, paid service or system-wide classpath modification is required.

2. Mental model: extension code joins the execution path

JMeter extension dependency flow

An extension changes both the executable code loaded into the generator and the JMX compatibility contract. Classpath location, API lifecycle and provenance therefore belong in the same evidence packet as the test plan.

flowchart TD
J[Apache JMeter core 5.6.3] --> C[Classpath/plugin discovery]
P[Verified third-party plugin or custom JAR] --> C
D[Utility/dependency JARs] --> C
C --> L[Component lifecycle]
L --> S[Sampler / function / listener behavior]
X[JMX class references + parameters] --> S
S --> T[Protocol/target or local generator work]
S --> R[JTL + jmeter.log + telemetry]
V[Compatibility/provenance lock] --> C
V --> X

JMeter core provides the engine and public extension APIs. Component/plugin JARs are discovered from the appropriate extension path; utility dependencies come from the dependency path. JMX stores class references/parameters. At execution, lifecycle methods run inside JMeter threads and may touch variables, properties, files, network, credentials or results. The lock records the exact code/version/hash needed to make that JMX reproducible.

3. Core, plugin, custom JAR and dependency

Type Definition Typical location/state
Apache JMeter distribution component JAR shipped as part of the Apache JMeter release, commonly ApacheJMeter_*.jar. Version follows the JMeter distribution.
Third-party plugin External maintained code that adds/changes JMeter behavior; not automatically Apache-supported. Usually component/plugin JAR in lib/ext or search_paths; dependencies elsewhere.
Custom JAR Your reviewed extension adapter or helper code. Versioned project artifact; component classes in an isolated extension path.
Utility/dependency JAR Library used by plugin/custom code rather than a JMeter TestElement itself. lib, user.classpath or plugin_dependency_paths, not casually copied to lib/ext.
JMX dependency Class/component/function required by the serialized test plan. Must map to an explicit core/plugin/custom version on every execution environment.

4. Current classpath rules

JMeter automatically discovers component/plugin JARs in JMETER_HOME/lib/ext. Utility/dependency JARs belong in JMETER_HOME/lib. Current properties also support search_paths for additional component/plugin classes and user.classpath/plugin_dependency_paths for dependencies. Normal JMeter startup uses java -jar, so the shell CLASSPATH variable is not the extension mechanism.

The course uses a project-local extensions/ directory through search_paths so rollback is “stop passing the path,” not “hunt for JARs copied into a shared installation.”

5. Java sampler lifecycle

The official Javadocs encourage subclassing AbstractJavaSamplerClient. JMeter creates a JavaSamplerClient instance for each virtual user/thread (and may create extra internal instances). setupTest() initializes that instance, runTest() executes each iteration, and teardownTest() cleans up. Per-instance fields are therefore naturally per-thread for that sampler instance; static mutable fields are still process-wide.

6. Functions have a different concurrency boundary

A JMeter Function occurrence is prepared once and can be executed by multiple threads. Current Javadocs explicitly warn that function execution must synchronize when it touches non-thread-safe objects. If per-thread function state is needed, use thread-local/JMeter-variable state deliberately. Do not copy Java-sampler lifecycle assumptions into Function code.

7. Extension state inventory

Boundary Questions before changing it
Generator Exact JMeter/Java, CPU/GC, active extension paths, configured/achieved load?
Thread/arrival Does extension maintain per-thread, shared-static, or arrival-scheduler state?
Tree/component scope Which TestElement/function/GUI class is required and where in the tree is it scoped?
Variables/properties/data Does extension read thread-local vars, process-global properties, files or static caches?
Protocol/session Does it create sockets/clients/pools/cookies/tokens or only perform local work?
Target What authorized target can it contact/mutate? Does it bypass existing guardrails?
Results Does it create SampleResults/listener telemetry or save sensitive data?
Credential/trust What files/env/secrets/JMX can extension code read? Is source/provenance trusted?
Validity What generator overhead/classpath drift could change latency/throughput conclusions?

8. Read-only inspection first

& "$env:JMETER_HOME\bin\jmeter.bat" -v
java -version

Get-ChildItem "$env:JMETER_HOME\lib\ext\*.jar" |
  Sort-Object Name |
  Select-Object Name,Length

Get-ChildItem "$env:JMETER_HOME\lib\*.jar" |
  Sort-Object Name |
  Select-Object Name,Length

Get-FileHash "$env:JMETER_HOME\lib\ext\*.jar" -Algorithm SHA256
Get-Content .\locks\extensions.lock.json -ErrorAction SilentlyContinue

Read jmeter.log before adding anything: startup/class-loading warnings are part of the baseline. In a distributed/CI/container environment inventory every engine/image, not just the controller.

9. Plugins Manager is optional third-party tooling

The current JMeter-Plugins.org Plugins Manager can install/update/uninstall plugins and can be automated. It is not Apache JMeter core. Its current documentation also describes anonymous usage statistics sent by default and a property to disable them. This course does not install it because the custom lab needs no third-party plugin. If your team adopts it, treat its own JAR/repository metadata and every selected plugin as supply-chain inputs: exact version, source, SHA-256, license/review and rollback.

10. DevOps connection

An extension turns a JMX from “configuration only” into a software dependency graph. The same practices used for application dependencies—version locks, hashes, source provenance, tests, compatibility matrices, staged upgrades and rollback—belong in performance-test operations.

Knowledge check

Where should a JMeter component/plugin JAR normally live?

Why is a custom sampler instance field usually safer than a static counter?

Can shell CLASSPATH be relied on to extend normal JMeter startup?

Why is a JMX dependency map useful?

Is Plugins Manager Apache JMeter core?

Next lesson

Build a tiny custom Java sampler safely

Lesson2 separates pure unit-testable logic from a thin JMeter API adapter, inventories JARs, creates a compatibility lock, runs a bounded loopback plan and proves rollback.

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against current primary/maintainer documentation on 2026-09-05. The mandatory runtime is Apache JMeter 5.6.3 with Java 17 and no third-party plugin. JMeter discovers JMeter component/plugin jars in JMETER_HOME/lib/ext; dependency/utility jars belong in JMETER_HOME/lib. Additional component/plugin paths can be provided with search_paths; utility/dependency paths use user.classpath or plugin_dependency_paths. The CLASSPATH environment variable does not affect normal JMeter startup because JMeter is launched with java -jar. Official Javadocs encourage custom Java samplers to extend AbstractJavaSamplerClient rather than implement JavaSamplerClient directly. JMeter creates a JavaSamplerClient instance per user/thread and calls setup/run/teardown around that thread's lifecycle. Functions differ: a function occurrence can be executed by multiple threads, so mutable non-thread-safe function state needs synchronization or thread-local design. Current JMeter best practices continue to prefer cached JSR223 Groovy over BeanShell for intensive scripting. The JMeter Plugins Manager is maintained by JMeter-Plugins.org, not by the Apache JMeter project; the mandatory lab intentionally installs none. If a team adopts it or any managed plugin, record the exact version, source and SHA-256 and review install/update changes before execution.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.