# Understanding the Jenkins Plugin Architecture and Extension Loading Mechanism

> Explore the Jenkins plugin architecture and how extensions are loaded using SezPoz annotations and ExtensionFinder. Discover how plugins register their implementations for runtime use within Jenkins.

- Repository: [Jenkins/jenkins](https://github.com/jenkinsci/jenkins)
- Tags: internals
- Published: 2026-06-19

---

**Jenkins uses a SezPoz-based annotation indexing system where plugins mark implementations with `@Extension`, which are discovered at runtime by `ExtensionFinder` and stored in type-specific `ExtensionList` registries.**

The Jenkins plugin architecture in the `jenkinsci/jenkins` repository provides a robust extensibility model that allows third-party code to enhance core functionality without modifying the source. This architecture relies on a sophisticated discovery mechanism that scans compiled artifacts for annotated components and dynamically loads them into the running application.

## Core Extension Contracts

### Extension Points as Interfaces

Every plugin capability starts with the **ExtensionPoint** marker interface. In [`core/src/main/java/hudson/ExtensionPoint.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/ExtensionPoint.java), this interface serves as the base contract that defines where plugins can hook into Jenkins core functionality. Plugin authors create new extension points by extending this interface, while implementers provide concrete classes that satisfy these contracts.

### Declaring Implementations with @Extension

Implementations are registered using the **`@Extension`** annotation found in [`core/src/main/java/hudson/Extension.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/Extension.java). This annotation can decorate classes, static factory methods, or static fields. It supports optional properties including `ordinal` for sorting priority and `dynamicLoadable` to control hot-reloading behavior.

```java
@Extension(ordinal = 100)
public class MyBuilder extends Builder {
    // Implementation automatically discovered at runtime
}

```

## How Extensions Are Discovered and Loaded

### The ExtensionFinder SPI

The **`ExtensionFinder`** abstract class in [`core/src/main/java/hudson/ExtensionFinder.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/ExtensionFinder.java) defines the Service Provider Interface for locating annotated objects. Its `find(Class<T> type, Hudson hudson)` method returns a collection of `ExtensionComponent<T>` objects. Jenkins ships with two primary implementations that handle different instantiation strategies.

### SezPoz Index-Based Discovery

The **`SezPoz`** finder (starting at line 675 in [`ExtensionFinder.java`](https://github.com/jenkinsci/jenkins/blob/main/ExtensionFinder.java)) reads a compile-time index generated by the SezPoz annotation processor. During the build phase, this processor creates index files in `META-INF/sezpoz/`. At runtime, when Jenkins reaches the **`PLUGINS_PREPARED`** milestone, the finder loads these indices via `Index.load(Extension.class, …)` and instantiates the discovered classes.

### GuiceFinder for Dependency Injection

The **`GuiceFinder`** (starting at line 378 in [`ExtensionFinder.java`](https://github.com/jenkinsci/jenkins/blob/main/ExtensionFinder.java)) provides Google Guice integration, allowing plugins to use dependency injection containers. This finder instantiates extensions through the Guice injector, enabling sophisticated wiring of plugin components with managed lifecycles.

## Extension Registration and Access

### ExtensionList as the Central Registry

The **`ExtensionList`** class in [`core/src/main/java/hudson/ExtensionList.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/ExtensionList.java) serves as the central registry holding all discovered instances for a specific extension point type. It uses lazy initialization—the first call to lookup methods triggers the `ensureLoaded()` method (line 300), which synchronizes on a global lock to prevent deadlocks during concurrent class initialization.

The registry populates from two sources: auto-discovered components obtained from the `ExtensionFinder`, and legacy manually added components maintained for backward compatibility.

### Accessing Extensions in Code

Developers retrieve implementations through static helper methods that resolve to the appropriate `ExtensionList`:

```java
// Get all implementations of a point
ExtensionList<Builder> allBuilders = ExtensionList.lookup(Builder.class);

// Get the singleton implementation (fails if not exactly one)
Builder theBuilder = ExtensionList.lookupSingleton(Builder.class);

// Get the first implementation according to ordinal sorting
Builder first = ExtensionList.lookupFirst(Builder.class);

```

### ExtensionComponent Wrappers

Each discovered instance is wrapped in an **`ExtensionComponent`** object (defined in [`core/src/main/java/hudson/ExtensionComponent.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/ExtensionComponent.java)). This wrapper holds the instance alongside its ordinal metadata, allowing the system to sort extensions according to their declared priority.

## Dynamic Loading and Hot-Reloading

When plugins are installed or updated at runtime, the `ExtensionFinder.refresh()` method returns an **`ExtensionComponentSet`** (from [`core/src/main/java/jenkins/ExtensionComponentSet.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/jenkins/ExtensionComponentSet.java)) containing only the new components. The `ExtensionList.refresh(delta)` method merges these into existing lists while preserving ordering and avoiding duplicate instances.

The **`dynamicLoadable`** attribute of `@Extension` controls whether Jenkins attempts to hot-reload the plugin on the fly or requires a restart to activate the changes.

## Summary

- **ExtensionPoint** interface in [`hudson/ExtensionPoint.java`](https://github.com/jenkinsci/jenkins/blob/main/hudson/ExtensionPoint.java) defines the contracts that plugins can implement.
- The **`@Extension`** annotation marks classes, methods, or fields for automatic discovery, supporting `ordinal` sorting and `dynamicLoadable` flags.
- **SezPoz** uses compile-time index files in `META-INF/sezpoz/` for fast lookup, while **GuiceFinder** enables dependency injection for complex component wiring.
- **ExtensionList** provides lazy-loading registries accessed via `lookup()`, `lookupSingleton()`, and `lookupFirst()` static methods.
- **ExtensionComponent** wraps instances with metadata, and **ExtensionComponentSet** handles incremental updates during hot-reloading.

## Frequently Asked Questions

### What is an ExtensionPoint in Jenkins?

An **ExtensionPoint** is a marker interface defined in [`core/src/main/java/hudson/ExtensionPoint.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/ExtensionPoint.java) that establishes a contract for extension points within the Jenkins plugin architecture. Plugin authors extend this interface to define new hook points, while other developers implement these interfaces to provide concrete functionality that the core system discovers and loads automatically.

### How does the @Extension annotation work?

The **`@Extension`** annotation registers a class, static method, or static field as an extension implementation. At compile time, the SezPoz processor indexes these annotations; at runtime, `ExtensionFinder` implementations locate these indices and instantiate the components. The annotation accepts an `ordinal` parameter for sorting and a `dynamicLoadable` parameter to control whether the extension supports hot-reloading without restart.

### Can Jenkins load plugins without restarting?

Yes, Jenkins supports **dynamic loading** when the `@Extension` annotation specifies `dynamicLoadable = true`. When a new plugin is installed, the `PluginManager` triggers `ExtensionFinder.refresh()`, which returns an `ExtensionComponentSet` of new components. The `ExtensionList.refresh()` method merges these into the running system, making extensions immediately available without requiring a full restart.

### What is the difference between SezPoz and GuiceFinder?

**SezPoz** is the default discovery mechanism that reads pre-compiled index files from `META-INF/sezpoz/` to quickly locate `@Extension` annotations, making it ideal for simple component registration. **GuiceFinder** integrates the Google Guice dependency injection framework, allowing plugins to define complex wiring and lifecycle management through Guice modules, which is necessary for components requiring sophisticated injection patterns.