# LabelBuilderFactory in Linkis: Implementing Custom Label Builders for Engine Type Routing

> Learn how to use LabelBuilderFactory in Linkis to implement custom label builders for engine type routing. Discover extensible label builders via classpath scanning for seamless customization without core code changes.

- Repository: [The Apache Software Foundation/linkis](https://github.com/apache/linkis)
- Tags: internals
- Published: 2026-02-25

---

**LabelBuilderFactory in Linkis** is the central interface that delegates label object creation to an ordered chain of `ExtensibleLabelBuilder` implementations, automatically discovered at runtime via classpath scanning to enable custom engine-type routing without modifying core code.

In Apache Linkis, labels are key-value pairs attached to job requests that drive routing decisions in the resource manager and engine selector. The **LabelBuilderFactory** decouples label instantiation from business logic, allowing you to inject custom routing rules by implementing the `ExtensibleLabelBuilder` interface.

## Understanding the LabelBuilderFactory Architecture

### Core Factory Interface and Default Implementation

The `LabelBuilderFactory` interface defines multiple `createLabel` method signatures for constructing labels from keys/values, input streams, or maps. According to the Apache Linkis source code in [`linkis-computation-governance/linkis-manager/linkis-label-common/src/main/java/org/apache/linkis/manager/label/builder/factory/LabelBuilderFactory.java`](https://github.com/apache/linkis/blob/main/linkis-computation-governance/linkis-manager/linkis-label-common/src/main/java/org/apache/linkis/manager/label/builder/factory/LabelBuilderFactory.java), these methods form the public API used throughout the computation governance layer.

The default implementation, `StdLabelBuilderFactory`, maintains a `LinkedList<ExtensibleLabelBuilder>` and iterates over it during label creation. Located in [`StdLabelBuilderFactory.java`](https://github.com/apache/linkis/blob/main/StdLabelBuilderFactory.java), this class sorts builders by their `getOrder()` value, consulting each builder's `canBuild` method until it finds a match.

### Automatic Builder Discovery via LabelBuilderFactoryContext

The `LabelBuilderFactoryContext` singleton manages factory lifecycle and builder registration. As implemented in [`LabelBuilderFactoryContext.java`](https://github.com/apache/linkis/blob/main/LabelBuilderFactoryContext.java), it lazily instantiates the concrete factory class (defaulting to `StdLabelBuilderFactory`) and uses Reflections to scan the classpath for all `ExtensibleLabelBuilder` implementations during initialization. This zero-configuration approach means any custom builder packaged in the runtime is automatically registered.

### The Builder Chain and Ordering Mechanism

The `ExtensibleLabelBuilder` interface in [`ExtensibleLabelBuilder.java`](https://github.com/apache/linkis/blob/main/ExtensibleLabelBuilder.java) specifies three critical methods: `canBuild` to determine capability, `build` to construct the label, and `getOrder` to establish precedence. Builders with lower order values are consulted first, allowing custom implementations to intercept label creation before the `DefaultGlobalLabelBuilder` (which uses `Integer.MAX_VALUE`) handles generic cases.

## Implementing a Custom Label Builder for Engine Type Routing

To implement custom engine-type routing, extend `AbstractGenericLabelBuilder` and override the critical contract methods defined in [`ExtensibleLabelBuilder.java`](https://github.com/apache/linkis/blob/main/ExtensibleLabelBuilder.java).

### Step 1: Extend AbstractGenericLabelBuilder

Create a class that inherits from `AbstractGenericLabelBuilder` (found in [`AbstractGenericLabelBuilder.java`](https://github.com/apache/linkis/blob/main/AbstractGenericLabelBuilder.java)). This base class provides default implementations for common builder operations, allowing you to focus on the routing logic.

### Step 2: Implement canBuild and getOrder

Override `canBuild(String key, Class<?> labelClass)` to return `true` for your custom label keys. Set `getOrder()` to a value lower than `Integer.MAX_VALUE` (used by the default global builder) to ensure priority execution. This ordering mechanism is defined in [`ExtensibleLabelBuilder.java`](https://github.com/apache/linkis/blob/main/ExtensibleLabelBuilder.java).

### Step 3: Construct the EngineTypeLabel

Implement the `build` method to create `EngineTypeLabel` instances. The following Scala example demonstrates routing to a custom `"spark-ml"` engine when detecting a specific key:

```scala
// src/main/scala/com/example/linkis/engine/MlEngineLabelBuilder.scala
package com.example.linkis.engine

import org.apache.linkis.manager.label.builder.AbstractGenericLabelBuilder
import org.apache.linkis.manager.label.entity.engine.{EngineTypeLabel, EngineType}
import org.apache.linkis.manager.label.utils.LabelKeyConstant

class MlEngineLabelBuilder extends AbstractGenericLabelBuilder {
  
  override def getOrder: Int = 10
  
  override def canBuild(labelKey: String, labelClass: Class[_]): Boolean = {
    labelKey == "mlEngine"
  }

  override def build(
      labelKey: String,
      valueObj: Object,
      labelClass: Class[_],
      valueTypes: java.lang.reflect.Type*
  ): EngineTypeLabel = {
    val engineName = Option(valueObj).map(_.toString).getOrElse("spark")
    val label = EngineTypeLabelCreator.createEngineTypeLabel(engineName)
    
    valueObj match {
      case m: java.util.Map[_, _] if m.containsKey("version") =>
        label.setVersion(m.get("version").toString)
      case _ =>
    }
    label
  }
}

```

This builder intercepts the `"mlEngine"` key and delegates to `EngineTypeLabelCreator` (from [`EngineTypeLabelCreator.java`](https://github.com/apache/linkis/blob/main/EngineTypeLabelCreator.java)) to construct the label, mirroring the pattern used in [`DefaultGlobalLabelBuilder.java`](https://github.com/apache/linkis/blob/main/DefaultGlobalLabelBuilder.java).

## Deployment and Runtime Integration

Package your builder in any module included in the Linkis runtime, such as a plugin JAR. The `LabelBuilderFactoryContext.labelBuilderInitRegister` method automatically discovers and registers the class via Reflections, requiring no XML configuration or SPI files.

When a client submits a job with the custom label:

```json
{
  "labels": [
    {"labelKey": "mlEngine", "value": "spark"},
    {"labelKey": "version", "value": "2.4.5"}
  ]
}

```

The factory iterates through the sorted builder chain, invokes your custom implementation, and produces an `EngineTypeLabel` that subsequent routing components treat as a standard engine type label.

## Advanced Configuration Options

If you need to replace the entire factory implementation rather than adding a single builder, set the configuration key `linkis.label.factory.class` in [`LabelCommonConfig.java`](https://github.com/apache/linkis/blob/main/LabelCommonConfig.java) to your custom factory class name. This bypasses the default `StdLabelBuilderFactory` entirely.

## Summary

- **LabelBuilderFactory** defines the contract for label creation in [`LabelBuilderFactory.java`](https://github.com/apache/linkis/blob/main/LabelBuilderFactory.java), with `StdLabelBuilderFactory` providing the default ordered-chain implementation.
- **LabelBuilderFactoryContext** handles automatic discovery of `ExtensibleLabelBuilder` implementations via classpath scanning at startup.
- Extend **AbstractGenericLabelBuilder** to implement custom routing logic with minimal boilerplate.
- Override **getOrder()** to control precedence in the builder chain; lower values execute first.
- Set **canBuild()** to filter for specific label keys that trigger your custom engine-type mapping.
- No additional configuration files are required; the Reflections-based scan picks up new builders automatically.

## Frequently Asked Questions

### What is the difference between LabelBuilderFactory and LabelBuilderFactoryContext in Linkis?

`LabelBuilderFactory` is the interface defining label creation APIs, while `LabelBuilderFactoryContext` is the singleton that instantiates the concrete factory and manages the lifecycle of all builders. The context performs the classpath scan and registers builders with the factory instance.

### How does Linkis determine which label builder to use for a specific key?

`StdLabelBuilderFactory` iterates over registered builders sorted by `getOrder()` value, calling `canBuild(String key, Class<?> labelClass)` on each until one returns `true`. The first matching builder wins the opportunity to construct the label.

### Can I override the default engine type builder without modifying Linkis core code?

Yes. By implementing `ExtensibleLabelBuilder` with an order value lower than the default global builder (`Integer.MAX_VALUE`), your custom builder will be consulted first. When your `canBuild` method matches the engine type key, you control the label construction entirely.

### Where should I place my custom label builder code so Linkis discovers it?

Package your class in any JAR included in the Linkis runtime classpath, such as a plugin module or `linkis-engineplugin` extension. The `LabelBuilderFactoryContext` uses Reflections to scan all packages for `ExtensibleLabelBuilder` implementations during initialization, so no explicit registration is required.